From 4c1a86cedb7d35116b525876bef9ece93c907b37 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 29 Sep 2019 18:02:08 +0200 Subject: [PATCH] Fixed build errors with latest libnx --- LICENSE | 678 +- Makefile | 466 +- README.md | 178 +- include/edizon.h | 32 +- include/guis/gui.hpp | 224 +- include/guis/gui_about.hpp | 34 +- include/guis/gui_cheats.hpp | 170 +- include/guis/gui_editor.hpp | 102 +- include/guis/gui_guide.hpp | 70 +- include/guis/gui_main.hpp | 72 +- include/guis/gui_tx_warning.hpp | 38 +- include/helpers/account.hpp | 68 +- include/helpers/config.hpp | 38 +- include/helpers/debugger.hpp | 48 +- include/helpers/dmntcht.h | 150 +- include/helpers/editor_config_parser.hpp | 90 +- include/helpers/encoding.hpp | 28 +- include/helpers/memory_dump.hpp | 72 +- include/helpers/save.hpp | 62 +- include/helpers/title.hpp | 76 +- include/helpers/util.h | 50 +- include/scripting/interpreter.hpp | 100 +- include/scripting/lua_interpreter.hpp | 110 +- include/scripting/python_interpreter.hpp | 106 +- include/theme.h | 50 +- include/types.h | 260 +- include/ui_elements/button.hpp | 68 +- include/ui_elements/list_selector.hpp | 76 +- include/ui_elements/message_box.hpp | 82 +- include/ui_elements/scroll_selector.hpp | 46 +- include/ui_elements/snackbar.hpp | 48 +- include/update_manager.hpp | 40 +- include/upload_manager.hpp | 46 +- include/widgets/widget.hpp | 140 +- include/widgets/widget_button.hpp | 44 +- include/widgets/widget_comment.hpp | 42 +- include/widgets/widget_list.hpp | 46 +- include/widgets/widget_string.hpp | 40 +- include/widgets/widget_switch.hpp | 46 +- include/widgets/widget_value.hpp | 44 +- libs/lua/LICENSE.md | 10 +- libs/lua/include/lapi.h | 48 +- libs/lua/include/lauxlib.h | 528 +- libs/lua/include/lcode.h | 176 +- libs/lua/include/lctype.h | 190 +- libs/lua/include/ldebug.h | 78 +- libs/lua/include/ldo.h | 116 +- libs/lua/include/lfunc.h | 122 +- libs/lua/include/lgc.h | 294 +- libs/lua/include/llex.h | 170 +- libs/lua/include/llimits.h | 646 +- libs/lua/include/lmem.h | 138 +- libs/lua/include/lobject.h | 1098 +- libs/lua/include/lopcodes.h | 594 +- libs/lua/include/lparser.h | 266 +- libs/lua/include/lprefix.h | 90 +- libs/lua/include/lstate.h | 506 +- libs/lua/include/lstring.h | 98 +- libs/lua/include/ltable.h | 132 +- libs/lua/include/ltm.h | 152 +- libs/lua/include/lua.h | 972 +- libs/lua/include/lua.hpp | 18 +- libs/lua/include/luaconf.h | 1574 +- libs/lua/include/lualib.h | 122 +- libs/lua/include/lundump.h | 64 +- libs/lua/include/lvm.h | 226 +- libs/lua/include/lzio.h | 132 +- libs/lua/source/lapi.c | 2598 +- libs/lua/source/lauxlib.c | 2086 +- libs/lua/source/lbaselib.c | 996 +- libs/lua/source/lbitlib.c | 466 +- libs/lua/source/lcode.c | 2406 +- libs/lua/source/lcorolib.c | 336 +- libs/lua/source/lctype.c | 110 +- libs/lua/source/ldblib.c | 912 +- libs/lua/source/ldebug.c | 1398 +- libs/lua/source/ldo.c | 1604 +- libs/lua/source/ldump.c | 430 +- libs/lua/source/lfunc.c | 302 +- libs/lua/source/lgc.c | 2358 +- libs/lua/source/linit.c | 134 +- libs/lua/source/liolib.c | 1552 +- libs/lua/source/llex.c | 1130 +- libs/lua/source/lmathlib.c | 820 +- libs/lua/source/lmem.c | 200 +- libs/lua/source/loadlib.c | 1580 +- libs/lua/source/lobject.c | 1044 +- libs/lua/source/lopcodes.c | 248 +- libs/lua/source/loslib.c | 818 +- libs/lua/source/lparser.c | 3300 +- libs/lua/source/lstate.c | 694 +- libs/lua/source/lstring.c | 496 +- libs/lua/source/lstrlib.c | 3168 +- libs/lua/source/ltable.c | 1376 +- libs/lua/source/ltablib.c | 900 +- libs/lua/source/ltm.c | 330 +- libs/lua/source/lundump.c | 558 +- libs/lua/source/lutf8lib.c | 512 +- libs/lua/source/lvm.c | 2644 +- libs/lua/source/lzio.c | 136 +- libs/minizip/include/CDirEntry.h | 430 +- libs/minizip/include/crypt.h | 260 +- libs/minizip/include/defs.h | 132 +- libs/minizip/include/ioapi.h | 354 +- libs/minizip/include/ioapi_buf.h | 108 +- libs/minizip/include/ioapi_mem.h | 110 +- libs/minizip/include/iowin32.h | 66 +- libs/minizip/include/tools.h | 40 +- libs/minizip/include/unzip.h | 632 +- libs/minizip/include/unzipper.h | 176 +- libs/minizip/include/zip.h | 400 +- libs/minizip/include/zipper.h | 86 +- libs/minizip/source/CDirEntry.cpp | 1244 +- libs/minizip/source/aes/Makefile | 36 +- libs/minizip/source/aes/aes.h | 396 +- libs/minizip/source/aes/aes_via_ace.h | 1082 +- libs/minizip/source/aes/aescrypt.c | 588 +- libs/minizip/source/aes/aeskey.c | 1096 +- libs/minizip/source/aes/aesopt.h | 1478 +- libs/minizip/source/aes/aestab.c | 782 +- libs/minizip/source/aes/aestab.h | 346 +- libs/minizip/source/aes/brg_endian.h | 252 +- libs/minizip/source/aes/brg_types.h | 438 +- libs/minizip/source/aes/entropy.c | 106 +- libs/minizip/source/aes/entropy.h | 32 +- libs/minizip/source/aes/fileenc.c | 286 +- libs/minizip/source/aes/fileenc.h | 242 +- libs/minizip/source/aes/hmac.c | 290 +- libs/minizip/source/aes/hmac.h | 206 +- libs/minizip/source/aes/prng.c | 310 +- libs/minizip/source/aes/prng.h | 164 +- libs/minizip/source/aes/pwd2key.c | 386 +- libs/minizip/source/aes/pwd2key.h | 114 +- libs/minizip/source/aes/sha1.c | 516 +- libs/minizip/source/aes/sha1.h | 146 +- libs/minizip/source/ioapi.c | 738 +- libs/minizip/source/ioapi_buf.c | 1028 +- libs/minizip/source/ioapi_mem.c | 384 +- libs/minizip/source/tools.cpp | 290 +- libs/minizip/source/unzip.c | 3780 +-- libs/minizip/source/unzipper.cpp | 1124 +- libs/minizip/source/zip.c | 4042 +-- libs/minizip/source/zipper.cpp | 632 +- libs/nanojpeg/include/nanojpeg.h | 122 +- libs/nanojpeg/source/nanojpeg.c | 1832 +- libs/nlohmann/LICENSE.md | 42 +- libs/nlohmann/json.hpp | 34600 ++++++++++----------- libs/nxpy/LICENSE.md | 10 +- libs/nxpy/include/Python-ast.h | 1202 +- libs/nxpy/include/Python.h | 270 +- libs/nxpy/include/abstract.h | 2570 +- libs/nxpy/include/accu.h | 74 +- libs/nxpy/include/asdl.h | 90 +- libs/nxpy/include/ast.h | 44 +- libs/nxpy/include/bitset.h | 64 +- libs/nxpy/include/bltinmodule.h | 28 +- libs/nxpy/include/boolobject.h | 68 +- libs/nxpy/include/bytearrayobject.h | 124 +- libs/nxpy/include/bytes_methods.h | 92 +- libs/nxpy/include/bytesobject.h | 258 +- libs/nxpy/include/cellobject.h | 58 +- libs/nxpy/include/ceval.h | 426 +- libs/nxpy/include/classobject.h | 116 +- libs/nxpy/include/code.h | 270 +- libs/nxpy/include/codecs.h | 472 +- libs/nxpy/include/compile.h | 146 +- libs/nxpy/include/complexobject.h | 138 +- libs/nxpy/include/datetime.h | 486 +- libs/nxpy/include/descrobject.h | 210 +- libs/nxpy/include/dictobject.h | 306 +- libs/nxpy/include/dtoa.h | 38 +- libs/nxpy/include/dynamic_annotations.h | 998 +- libs/nxpy/include/enumobject.h | 34 +- libs/nxpy/include/errcode.h | 76 +- libs/nxpy/include/eval.h | 54 +- libs/nxpy/include/fileobject.h | 94 +- libs/nxpy/include/fileutils.h | 284 +- libs/nxpy/include/floatobject.h | 256 +- libs/nxpy/include/frameobject.h | 190 +- libs/nxpy/include/funcobject.h | 178 +- libs/nxpy/include/genobject.h | 146 +- libs/nxpy/include/graminit.h | 174 +- libs/nxpy/include/grammar.h | 186 +- libs/nxpy/include/import.h | 260 +- libs/nxpy/include/intrcheck.h | 42 +- libs/nxpy/include/iterobject.h | 50 +- libs/nxpy/include/listobject.h | 162 +- libs/nxpy/include/longintrepr.h | 206 +- libs/nxpy/include/longobject.h | 414 +- libs/nxpy/include/marshal.h | 56 +- libs/nxpy/include/memoryobject.h | 140 +- libs/nxpy/include/metagrammar.h | 36 +- libs/nxpy/include/methodobject.h | 188 +- libs/nxpy/include/modsupport.h | 310 +- libs/nxpy/include/moduleobject.h | 170 +- libs/nxpy/include/namespaceobject.h | 34 +- libs/nxpy/include/node.h | 88 +- libs/nxpy/include/object.h | 2130 +- libs/nxpy/include/objimpl.h | 726 +- libs/nxpy/include/odictobject.h | 86 +- libs/nxpy/include/opcode.h | 284 +- libs/nxpy/include/osdefs.h | 94 +- libs/nxpy/include/parsetok.h | 216 +- libs/nxpy/include/patchlevel.h | 70 +- libs/nxpy/include/pgen.h | 36 +- libs/nxpy/include/pgenheaders.h | 84 +- libs/nxpy/include/py_curses.h | 354 +- libs/nxpy/include/pyarena.h | 128 +- libs/nxpy/include/pyatomic.h | 500 +- libs/nxpy/include/pycapsule.h | 118 +- libs/nxpy/include/pyconfig.h | 3086 +- libs/nxpy/include/pyctype.h | 66 +- libs/nxpy/include/pydebug.h | 72 +- libs/nxpy/include/pyerrors.h | 950 +- libs/nxpy/include/pyexpat.h | 106 +- libs/nxpy/include/pyfpe.h | 352 +- libs/nxpy/include/pygetopt.h | 42 +- libs/nxpy/include/pyhash.h | 298 +- libs/nxpy/include/pylifecycle.h | 248 +- libs/nxpy/include/pymacconfig.h | 204 +- libs/nxpy/include/pymacro.h | 182 +- libs/nxpy/include/pymath.h | 424 +- libs/nxpy/include/pymem.h | 376 +- libs/nxpy/include/pyport.h | 1818 +- libs/nxpy/include/pystate.h | 558 +- libs/nxpy/include/pystrcmp.h | 46 +- libs/nxpy/include/pystrhex.h | 34 +- libs/nxpy/include/pystrtod.h | 82 +- libs/nxpy/include/pythonrun.h | 390 +- libs/nxpy/include/pythread.h | 186 +- libs/nxpy/include/pytime.h | 386 +- libs/nxpy/include/rangeobject.h | 54 +- libs/nxpy/include/setobject.h | 214 +- libs/nxpy/include/sliceobject.h | 100 +- libs/nxpy/include/structmember.h | 152 +- libs/nxpy/include/structseq.h | 98 +- libs/nxpy/include/symtable.h | 234 +- libs/nxpy/include/sysmodule.h | 86 +- libs/nxpy/include/token.h | 180 +- libs/nxpy/include/traceback.h | 146 +- libs/nxpy/include/tupleobject.h | 146 +- libs/nxpy/include/typeslots.h | 170 +- libs/nxpy/include/ucnhash.h | 72 +- libs/nxpy/include/unicodeobject.h | 4570 +-- libs/nxpy/include/warnings.h | 108 +- libs/nxpy/include/weakrefobject.h | 172 +- romfs/guide/1/1/config.json | 38 +- romfs/guide/1/1/text.txt | 12 +- romfs/guide/1/2/auto_updater.txt | 4 +- romfs/guide/1/2/config.json | 34 +- romfs/guide/1/2/debug_logs.txt | 6 +- romfs/guide/1/3/config.json | 38 +- romfs/guide/1/3/text.txt | 8 +- romfs/guide/1/4/config.json | 54 +- romfs/guide/1/4/text.txt | 14 +- romfs/guide/1/5/config.json | 22 +- romfs/guide/1/5/text.txt | 20 +- romfs/guide/2/10/config.json | 22 +- romfs/guide/2/10/text.txt | 32 +- romfs/guide/2/6/config.json | 38 +- romfs/guide/2/6/text.txt | 10 +- romfs/guide/2/7/config.json | 22 +- romfs/guide/2/7/text.txt | 18 +- romfs/guide/2/8/config.json | 44 +- romfs/guide/2/9/config.json | 44 +- source/guis/gui.cpp | 1414 +- source/guis/gui_about.cpp | 336 +- source/guis/gui_cheats.cpp | 2906 +- source/guis/gui_editor.cpp | 1534 +- source/guis/gui_guide.cpp | 268 +- source/guis/gui_main.cpp | 998 +- source/guis/gui_tx_warning.cpp | 100 +- source/helpers/account.cpp | 116 +- source/helpers/config.cpp | 62 +- source/helpers/debugger.cpp | 114 +- source/helpers/dmntcht.c | 1262 +- source/helpers/editor_config_parser.cpp | 386 +- source/helpers/encoding.cpp | 250 +- source/helpers/memory_dump.cpp | 350 +- source/helpers/save.cpp | 902 +- source/helpers/title.cpp | 210 +- source/helpers/util.c | 242 +- source/main.cpp | 740 +- source/scripting/interpreter.cpp | 168 +- source/scripting/lua_interpreter.cpp | 536 +- source/scripting/python_interpreter.cpp | 700 +- source/theme.c | 68 +- source/ui_elements/button.cpp | 80 +- source/ui_elements/list_selector.cpp | 246 +- source/ui_elements/message_box.cpp | 242 +- source/ui_elements/snackbar.cpp | 112 +- source/update_manager.cpp | 518 +- source/upload_manager.cpp | 362 +- source/widgets/widget.cpp | 332 +- source/widgets/widget_button.cpp | 74 +- source/widgets/widget_comment.cpp | 64 +- source/widgets/widget_list.cpp | 132 +- source/widgets/widget_string.cpp | 82 +- source/widgets/widget_switch.cpp | 114 +- source/widgets/widget_value.cpp | 170 +- 300 files changed, 81308 insertions(+), 81308 deletions(-) diff --git a/LICENSE b/LICENSE index d159169d..89e08fb0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 - - 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. - - - Copyright (C) - - 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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. - - , 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 Lesser General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 + + 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. + + + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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. + + , 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 Lesser General +Public License instead of this License. diff --git a/Makefile b/Makefile index cea1c8a4..e6a48bd7 100644 --- a/Makefile +++ b/Makefile @@ -1,233 +1,233 @@ -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- - -ifeq ($(strip $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") -endif - -TOPDIR ?= $(CURDIR) -include $(DEVKITPRO)/libnx/switch_rules - -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# DATA is a list of directories containing data files -# INCLUDES is a list of directories containing header files -# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". -# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) -# -# NO_ICON: if set to anything, do not use icon. -# NO_NACP: if set to anything, no .nacp file is generated. -# APP_TITLE is the name of the app stored in the .nacp file (Optional) -# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) -# APP_VERSION is the version of the app stored in the .nacp file (Optional) -# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) -# ICON is the filename of the icon (.jpg), relative to the project folder. -# If not set, it attempts to use one of the following (in this order): -# - .jpg -# - icon.jpg -# - /default_icon.jpg -#--------------------------------------------------------------------------------- -VERSION_MAJOR := 3 -VERSION_MINOR := 1 -VERSION_MICRO := 0 -NIGHTLY := 1 - -APP_TITLE := EdiZon -APP_AUTHOR := WerWolv - -ifeq ($(NIGHTLY), 1) - APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} - Nightly -else - APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} -endif - -TARGET := $(notdir $(CURDIR)) -OUTDIR := out -BUILD := build -SOURCES := source source/widgets source/guis source/scripting source/ui_elements source/helpers libs/lua/source libs/nanojpeg/source libs/minizip/source -DATA := data -INCLUDES := include libs/nxpy/include libs/lua/include libs/nlohmann libs/nanojpeg/include libs/minizip/include -EXEFS_SRC := exefs_src -ROMFS := romfs - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- -ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE - -null := -SPACE := $(null) $(null) - -CFLAGS := -g -Wall -O3 -ffunction-sections \ - $(ARCH) $(DEFINES) \ - -DVERSION_MAJOR=${VERSION_MAJOR} \ - -DVERSION_MINOR=${VERSION_MINOR} \ - -DVERSION_MICRO=${VERSION_MICRO} \ - -DVERSION_STRING=\"$(subst $(SPACE),\$(SPACE),${APP_VERSION})\" - -CFLAGS += $(INCLUDE) -D__SWITCH__ -I$(PORTLIBS)/include/freetype2 $(pkg-config --cflags --libs python3) - -CXXFLAGS := $(CFLAGS) -fexceptions -std=gnu++17 - -ASFLAGS := -g $(ARCH) -LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-no-as-needed,-Map,$(notdir $*.map) - -LIBS := -lpython3.5 -lnx -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -lz -lstdc++fs `freetype-config --libs` - -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := $(CURDIR)/libs/nxpy $(PORTLIBS) $(LIBNX) - - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(OUTDIR)/EdiZon -export TOPDIR := $(CURDIR) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -export DEPSDIR := $(CURDIR)/$(BUILD) - -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- - -export OFILES_BIN := $(addsuffix .o,$(BINFILES)) -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_BIN) $(OFILES_SRC) -export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) - -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) - -ifeq ($(strip $(ICON)),) - icons := $(wildcard *.jpg) - ifneq (,$(findstring $(TARGET).jpg,$(icons))) - export APP_ICON := $(TOPDIR)/$(TARGET).jpg - else - ifneq (,$(findstring icon.jpg,$(icons))) - export APP_ICON := $(TOPDIR)/icon.jpg - endif - endif -else - export APP_ICON := $(TOPDIR)/$(ICON) -endif - -ifeq ($(strip $(NO_ICON)),) - export NROFLAGS += --icon=$(APP_ICON) -endif - -ifeq ($(strip $(NO_NACP)),) - export NROFLAGS += --nacp=$(CURDIR)/$(OUTDIR)/EdiZon.nacp -endif - -ifneq ($(APP_TITLEID),) - export NACPFLAGS += --titleid=$(APP_TITLEID) -endif - -ifneq ($(ROMFS),) - export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) -endif - -PC = $(shell printf "%d" ${pc}) -BASE = $(shell printf "%d" ${b}) -ADDR = $(shell printf "%x" $(shell echo $(PC)-$(BASE) | bc)) - -.PHONY: $(BUILD) clean all run errline $(ROMFS) - -#--------------------------------------------------------------------------------- -all: $(BUILD) $(ROMFS) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ $(BUILD) $(OUTDIR) - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#-------------------------------------------------------------------------------- -run: $(BUILD) - @echo Starting nxlink - @nxlink $(OUTPUT).nro -s -p "EdiZon/EdiZon.nro" - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(OUTDIR) - -#--------------------------------------------------------------------------------- -errline: - @aarch64-none-elf-addr2line -e $(OUTPUT).elf -f -p -C -a 0x$(ADDR) - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).pfs0 $(OUTPUT).nro - -$(OUTPUT).pfs0 : $(OUTPUT).nso - -$(OUTPUT).nso : $(OUTPUT).elf - -ifeq ($(strip $(NO_NACP)),) -$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp -else -$(OUTPUT).nro : $(OUTPUT).elf -endif - -$(OUTPUT).elf : $(OFILES) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - -#--------------------------------------------------------------------------------- -%.nxfnt.o : %.nxfnt -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +#--------------------------------------------------------------------------------- +VERSION_MAJOR := 3 +VERSION_MINOR := 1 +VERSION_MICRO := 0 +NIGHTLY := 1 + +APP_TITLE := EdiZon +APP_AUTHOR := WerWolv + +ifeq ($(NIGHTLY), 1) + APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} - Nightly +else + APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO} +endif + +TARGET := $(notdir $(CURDIR)) +OUTDIR := out +BUILD := build +SOURCES := source source/widgets source/guis source/scripting source/ui_elements source/helpers libs/lua/source libs/nanojpeg/source libs/minizip/source +DATA := data +INCLUDES := include libs/nxpy/include libs/lua/include libs/nlohmann libs/nanojpeg/include libs/minizip/include +EXEFS_SRC := exefs_src +ROMFS := romfs + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE + +null := +SPACE := $(null) $(null) + +CFLAGS := -g -Wall -O3 -ffunction-sections \ + $(ARCH) $(DEFINES) \ + -DVERSION_MAJOR=${VERSION_MAJOR} \ + -DVERSION_MINOR=${VERSION_MINOR} \ + -DVERSION_MICRO=${VERSION_MICRO} \ + -DVERSION_STRING=\"$(subst $(SPACE),\$(SPACE),${APP_VERSION})\" + +CFLAGS += $(INCLUDE) -D__SWITCH__ -I$(PORTLIBS)/include/freetype2 $(pkg-config --cflags --libs python3) + +CXXFLAGS := $(CFLAGS) -fexceptions -std=gnu++17 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-no-as-needed,-Map,$(notdir $*.map) + +LIBS := -lpython3.5 -lnx -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -lz -lstdc++fs `freetype-config --libs` + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR)/libs/nxpy $(PORTLIBS) $(LIBNX) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(OUTDIR)/EdiZon +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.jpg) + ifneq (,$(findstring $(TARGET).jpg,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).jpg + else + ifneq (,$(findstring icon.jpg,$(icons))) + export APP_ICON := $(TOPDIR)/icon.jpg + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_ICON)),) + export NROFLAGS += --icon=$(APP_ICON) +endif + +ifeq ($(strip $(NO_NACP)),) + export NROFLAGS += --nacp=$(CURDIR)/$(OUTDIR)/EdiZon.nacp +endif + +ifneq ($(APP_TITLEID),) + export NACPFLAGS += --titleid=$(APP_TITLEID) +endif + +ifneq ($(ROMFS),) + export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) +endif + +PC = $(shell printf "%d" ${pc}) +BASE = $(shell printf "%d" ${b}) +ADDR = $(shell printf "%x" $(shell echo $(PC)-$(BASE) | bc)) + +.PHONY: $(BUILD) clean all run errline $(ROMFS) + +#--------------------------------------------------------------------------------- +all: $(BUILD) $(ROMFS) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ $(BUILD) $(OUTDIR) + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#-------------------------------------------------------------------------------- +run: $(BUILD) + @echo Starting nxlink + @nxlink $(OUTPUT).nro -s -p "EdiZon/EdiZon.nro" + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTDIR) + +#--------------------------------------------------------------------------------- +errline: + @aarch64-none-elf-addr2line -e $(OUTPUT).elf -f -p -C -a 0x$(ADDR) + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).pfs0 $(OUTPUT).nro + +$(OUTPUT).pfs0 : $(OUTPUT).nso + +$(OUTPUT).nso : $(OUTPUT).elf + +ifeq ($(strip $(NO_NACP)),) +$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp +else +$(OUTPUT).nro : $(OUTPUT).elf +endif + +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.nxfnt.o : %.nxfnt +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/README.md b/README.md index 067a9bcc..55a8197d 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,89 @@ -# EdiZon -


- Latest Release - Discord Server - Build Status -

- -A Homebrew save file dumper, injector and on-console editor for Horizon, the OS of the Nintendo Switch. - -# Overview - EdiZon consists of 3 different main functionalities. - - **Save file management** - - Extraction of game saves. - - Injection of extracted game saves (Your own and your friends save files). - - Uploading of savefiles directly to https://anonfile.com. - - Batch extraction of all save files of all games on the system. - - **Save file editing** - - Easy to use, scriptable and easily expandable on-console save editing. - - Lua and Python script support. - - Built-in save editor updater. - - **On-the-fly memory editing** - - Cheat Engine like RAM editing. - - Freezing of values in RAM via Atmosphère's cheat module. - - Interface for loading, managing and updating Atmosphère cheats. - - All packed into one easy to use and easy to install Homebrew. - -# Images -

-

-

-

- -# Save editor Config and Script files - - To download working Editor Config and Editor Script files, visit [this repository](https://github.com/WerWolv/EdiZon_ConfigsAndScripts/tree/master) - - Check out our [Wiki page](https://github.com/WerWolv/EdiZon/wiki) for more information on how to build your own Editor Config and Editor Script files. - -# How to install - - 1. Download the latest release from the [GitHub release page](https://github.com/WerWolv/EdiZon/releases/latest). - 2. Unpack the downloaded zip file, put the files on your Nintendo Switch's SD card and let the folders merge. - 3. Use a free open source CFW like [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere) to launch the hbmenu and start EdiZon from there. - 1. If you want to use the cheat manager you absolutely have to use [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere) as only their cheats are supported. - 2. For the best experience, open the `/atmosphere/system_settings.ini` file and change `dmnt_cheats_enabled_by_default = u8!0x1` to `dmnt_cheats_enabled_by_default = u8!0x0`. - - -# How to compile - - 1. Clone the EdiZon repo to your computer using `git clone https://github.com/WerWolv/EdiZon`. - 2. Download and install devkitA64. It comes bundled with the [devkitPro](https://devkitpro.org) toolchain. - 3. Use the pacman package manager that comes with devkitPro to download and install libNX, portlibs (`switch-portlibs`) and freetype2 (`switch-freetype`). - 4. The rest of the compilation works using the `make` command. - -# Discord - - For support with the usage of EdiZon or the creation of save editor configs and scripts, feel free to join the EdiZon server on Discord: https://discord.gg/qyA38T8 - -# Credits - - Thanks to... - - - [devkitPro](https://devkitpro.org) for their amazing toolchain! - - [3096](https://github.com/3096) for [save dumping/injecting](https://github.com/3096/nut) - - [Bernardo Giordano](https://github.com/BernardoGiordano) for some code from [Checkpoint](https://github.com/BernardoGiordano/Checkpoint). - - [SwitchBrew](https://switchbrew.org/) for the [Homebrew Launcher](https://github.com/switchbrew/nx-hbmenu) GUI and shared font code. - - [thomasnet-mc](https://github.com/thomasnet-mc/) for most of the save backup and restore code and the updater script. - - [trueicecold](https://github.com/trueicecold) for batch backups and the editable-only mode. - - [onepiecefreak](https://github.com/onepiecefreak3) for the edizon debugger and LOTS of reviewing implementations. - - [Jojo](https://github.com/drdrjojo) for the Travis CI configuration and the config creator. - - [Ac_K](https://github.com/AcK77) for help with the server side update scripts and the EdiZon save website. - - [jakibaki](https://github.com/jakibaki) for his massive help with the implementation of RAM editing and sys-netcheat which was used as inspiration. - - [SciresM](https://github.com/SciresM) for the aarch64 hardware accelerated SHA256 code, his implementation of the Atmosphère cheat engine and his support during development. - - **kardch** for the beautiful current icon. - - **bernv3** for the beautiful old icon. - - **All config creators** for bringing this project to life! - -
- - - [nlohmann](https://github.com/nlohmann) for his great json library. - - [Martin J. Fiedler](https://svn.emphy.de/nanojpeg/trunk/nanojpeg/nanojpeg.c) for the nanojpeg JPEG decoding library. - - [Lua](https://www.lua.org/) for their scripting language. - - [Python](https://www.python.org/) and [nx-python](https://github.com/nx-python) for their scripting language respectively their python port to the switch. - - -
-

-

+# EdiZon +


+ Latest Release + Discord Server + Build Status +

+ +A Homebrew save file dumper, injector and on-console editor for Horizon, the OS of the Nintendo Switch. + +# Overview + EdiZon consists of 3 different main functionalities. + - **Save file management** + - Extraction of game saves. + - Injection of extracted game saves (Your own and your friends save files). + - Uploading of savefiles directly to https://anonfile.com. + - Batch extraction of all save files of all games on the system. + - **Save file editing** + - Easy to use, scriptable and easily expandable on-console save editing. + - Lua and Python script support. + - Built-in save editor updater. + - **On-the-fly memory editing** + - Cheat Engine like RAM editing. + - Freezing of values in RAM via Atmosphère's cheat module. + - Interface for loading, managing and updating Atmosphère cheats. + + All packed into one easy to use and easy to install Homebrew. + +# Images +

+

+

+

+ +# Save editor Config and Script files + + To download working Editor Config and Editor Script files, visit [this repository](https://github.com/WerWolv/EdiZon_ConfigsAndScripts/tree/master) + + Check out our [Wiki page](https://github.com/WerWolv/EdiZon/wiki) for more information on how to build your own Editor Config and Editor Script files. + +# How to install + + 1. Download the latest release from the [GitHub release page](https://github.com/WerWolv/EdiZon/releases/latest). + 2. Unpack the downloaded zip file, put the files on your Nintendo Switch's SD card and let the folders merge. + 3. Use a free open source CFW like [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere) to launch the hbmenu and start EdiZon from there. + 1. If you want to use the cheat manager you absolutely have to use [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere) as only their cheats are supported. + 2. For the best experience, open the `/atmosphere/system_settings.ini` file and change `dmnt_cheats_enabled_by_default = u8!0x1` to `dmnt_cheats_enabled_by_default = u8!0x0`. + + +# How to compile + + 1. Clone the EdiZon repo to your computer using `git clone https://github.com/WerWolv/EdiZon`. + 2. Download and install devkitA64. It comes bundled with the [devkitPro](https://devkitpro.org) toolchain. + 3. Use the pacman package manager that comes with devkitPro to download and install libNX, portlibs (`switch-portlibs`) and freetype2 (`switch-freetype`). + 4. The rest of the compilation works using the `make` command. + +# Discord + + For support with the usage of EdiZon or the creation of save editor configs and scripts, feel free to join the EdiZon server on Discord: https://discord.gg/qyA38T8 + +# Credits + + Thanks to... + + - [devkitPro](https://devkitpro.org) for their amazing toolchain! + - [3096](https://github.com/3096) for [save dumping/injecting](https://github.com/3096/nut) + - [Bernardo Giordano](https://github.com/BernardoGiordano) for some code from [Checkpoint](https://github.com/BernardoGiordano/Checkpoint). + - [SwitchBrew](https://switchbrew.org/) for the [Homebrew Launcher](https://github.com/switchbrew/nx-hbmenu) GUI and shared font code. + - [thomasnet-mc](https://github.com/thomasnet-mc/) for most of the save backup and restore code and the updater script. + - [trueicecold](https://github.com/trueicecold) for batch backups and the editable-only mode. + - [onepiecefreak](https://github.com/onepiecefreak3) for the edizon debugger and LOTS of reviewing implementations. + - [Jojo](https://github.com/drdrjojo) for the Travis CI configuration and the config creator. + - [Ac_K](https://github.com/AcK77) for help with the server side update scripts and the EdiZon save website. + - [jakibaki](https://github.com/jakibaki) for his massive help with the implementation of RAM editing and sys-netcheat which was used as inspiration. + - [SciresM](https://github.com/SciresM) for the aarch64 hardware accelerated SHA256 code, his implementation of the Atmosphère cheat engine and his support during development. + - **kardch** for the beautiful current icon. + - **bernv3** for the beautiful old icon. + - **All config creators** for bringing this project to life! + +
+ + - [nlohmann](https://github.com/nlohmann) for his great json library. + - [Martin J. Fiedler](https://svn.emphy.de/nanojpeg/trunk/nanojpeg/nanojpeg.c) for the nanojpeg JPEG decoding library. + - [Lua](https://www.lua.org/) for their scripting language. + - [Python](https://www.python.org/) and [nx-python](https://github.com/nx-python) for their scripting language respectively their python port to the switch. + + +
+

+

diff --git a/include/edizon.h b/include/edizon.h index 84d1501c..5e0b2ddf 100644 --- a/include/edizon.h +++ b/include/edizon.h @@ -1,17 +1,17 @@ -#pragma once - -#include - -/* || EDIZON COMPILE TIME SETTINGS || */ - -/* The EdiZon folder base path on the SD card */ -#define EDIZON_DIR "/switch/EdiZon" - -/* Whether the splash screen should be displayed on launch */ -#define SPLASH_ENABLED 1 - -/* Current web API version */ -#define API_VERSION "v3" - -/* Web API URL */ +#pragma once + +#include + +/* || EDIZON COMPILE TIME SETTINGS || */ + +/* The EdiZon folder base path on the SD card */ +#define EDIZON_DIR "/switch/EdiZon" + +/* Whether the splash screen should be displayed on launch */ +#define SPLASH_ENABLED 1 + +/* Current web API version */ +#define API_VERSION "v3" + +/* Web API URL */ #define EDIZON_URL "http://api.edizon.werwolv.net/" API_VERSION \ No newline at end of file diff --git a/include/guis/gui.hpp b/include/guis/gui.hpp index 42cb81a0..438ce9d6 100644 --- a/include/guis/gui.hpp +++ b/include/guis/gui.hpp @@ -1,113 +1,113 @@ -#pragma once - -#include -#include -#include - -#include "helpers/title.hpp" - -#include "ui_elements/snackbar.hpp" -#include "ui_elements/list_selector.hpp" -#include "ui_elements/message_box.hpp" - -#include "theme.h" -#include "types.h" - -#include -#include FT_FREETYPE_H - -#define FONT_FACES_MAX PlSharedFontType_Total - -#define fontHuge 5 -#define fontTitle 4 -#define font24 3 -#define font20 2 -#define font14 1 - -enum gui_t { - GUI_INVALID, - GUI_MAIN, - GUI_EDITOR, - GUI_TX_WARNING, - GUI_CHEATS, - GUI_GUIDE, - GUI_ABOUT -}; - -class Gui { -public: - static inline enum gui_t g_nextGui = GUI_INVALID; - - u8 *framebuffer; - static inline Framebuffer g_fb_obj; - static inline u32 g_framebuffer_width = 1280; - static inline u32 g_framebuffer_height = 720; - - static inline bool g_splashDisplayed = false; - static inline bool g_requestExit = false; - - static inline Snackbar *g_currSnackbar = nullptr; - static inline ListSelector *g_currListSelector = nullptr; - static inline MessageBox *g_currMessageBox = nullptr; - - Gui(); - virtual ~Gui(); - - virtual void update(); - virtual void draw() = 0; - virtual void onInput(u32 kdown) = 0; - virtual void onTouch(touchPosition &touch) = 0; - virtual void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) = 0; - - static void resizeImage(u8* in, u8* out, size_t src_width, size_t src_height, size_t dest_width, size_t dest_height); - static std::vector split(const std::string& s, const char& c); - inline u8 blendColor(u32 src, u32 dst, u8 alpha); - color_t makeColor(u8 r, u8 g, u8 b, u8 a); - void drawRectangle(s16 x, s16 y, s16 w, s16 h, color_t color); - void drawRectangled(s16 x, s16 y, s16 w, s16 h, color_t color); - - bool fontInit(); - void fontExit(); - - void drawText(u32 font, s16 x, s16 y, color_t clr, const char* text); - void drawTextAligned(u32 font, s16 x, s16 y, color_t clr, const char* text, TextAlignment alignment); - void drawTextTruncate(u32 font, s16 x, s16 y, color_t clr, const char* text, u32 max_width, const char* end_text); - void getTextDimensions(u32 font, const char* text, u32* width_out, u32* height_out); - - void drawImage(s16 x, s16 y, s16 width, s16 height, const u8 *image, ImageMode mode); - void drawImage(s16 x, s16 y, s16 startx, s16 starty, s16 width, s16 height, const u8 *image, ImageMode mode); - void drawShadow(s16 x, s16 y, s16 width, s16 height); - void drawTooltip(s16 x, s16 y, const char *text, color_t backgroundColor, color_t textColor, u8 alpha, bool flipped); - - static bool requestKeyboardInput(std::string headerText, std::string subHeaderText, std::string initialText, SwkbdType type, char *out_text, size_t maxLength); - static u128 requestPlayerSelection(); - static void requestErrorMessage(Result result); - -protected: - void beginDraw(); - void endDraw(); - -private: - FT_Error m_fontLibret, m_fontFacesRet[FONT_FACES_MAX]; - FT_Library m_fontLibrary; - FT_Face m_fontFaces[FONT_FACES_MAX]; - FT_Face m_fontLastUsedFace; - size_t m_fontFacesTotal; - - std::unordered_map> m_stringDimensions; - - void drawText_(u32 font, s16 x, s16 y, color_t clr, const char* text, s32 max_width, const char* end_text); - inline void draw4PixelsRaw(s16 x, s16 y, color_t clr); - inline bool fontLoadGlyph(glyph_t* glyph, u32 font, u32 codepoint); - void drawGlyph(s16 x, s16 y, color_t clr, const glyph_t* glyph); - bool setFontType(u32 font); - inline u8 decodeByte(const char** ptr); - inline s8 decodeUTF8Cont(const char** ptr); - inline u32 decodeUTF8(const char** ptr); - inline void drawPixel(s16 x, s16 y, color_t clr); -}; - -#define COLOR_WHITE makeColor(255, 255, 255, 255) -#define COLOR_BLACK makeColor(0, 0, 0, 255) - +#pragma once + +#include +#include +#include + +#include "helpers/title.hpp" + +#include "ui_elements/snackbar.hpp" +#include "ui_elements/list_selector.hpp" +#include "ui_elements/message_box.hpp" + +#include "theme.h" +#include "types.h" + +#include +#include FT_FREETYPE_H + +#define FONT_FACES_MAX PlSharedFontType_Total + +#define fontHuge 5 +#define fontTitle 4 +#define font24 3 +#define font20 2 +#define font14 1 + +enum gui_t { + GUI_INVALID, + GUI_MAIN, + GUI_EDITOR, + GUI_TX_WARNING, + GUI_CHEATS, + GUI_GUIDE, + GUI_ABOUT +}; + +class Gui { +public: + static inline enum gui_t g_nextGui = GUI_INVALID; + + u8 *framebuffer; + static inline Framebuffer g_fb_obj; + static inline u32 g_framebuffer_width = 1280; + static inline u32 g_framebuffer_height = 720; + + static inline bool g_splashDisplayed = false; + static inline bool g_requestExit = false; + + static inline Snackbar *g_currSnackbar = nullptr; + static inline ListSelector *g_currListSelector = nullptr; + static inline MessageBox *g_currMessageBox = nullptr; + + Gui(); + virtual ~Gui(); + + virtual void update(); + virtual void draw() = 0; + virtual void onInput(u32 kdown) = 0; + virtual void onTouch(touchPosition &touch) = 0; + virtual void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) = 0; + + static void resizeImage(u8* in, u8* out, size_t src_width, size_t src_height, size_t dest_width, size_t dest_height); + static std::vector split(const std::string& s, const char& c); + inline u8 blendColor(u32 src, u32 dst, u8 alpha); + color_t makeColor(u8 r, u8 g, u8 b, u8 a); + void drawRectangle(s16 x, s16 y, s16 w, s16 h, color_t color); + void drawRectangled(s16 x, s16 y, s16 w, s16 h, color_t color); + + bool fontInit(); + void fontExit(); + + void drawText(u32 font, s16 x, s16 y, color_t clr, const char* text); + void drawTextAligned(u32 font, s16 x, s16 y, color_t clr, const char* text, TextAlignment alignment); + void drawTextTruncate(u32 font, s16 x, s16 y, color_t clr, const char* text, u32 max_width, const char* end_text); + void getTextDimensions(u32 font, const char* text, u32* width_out, u32* height_out); + + void drawImage(s16 x, s16 y, s16 width, s16 height, const u8 *image, ImageMode mode); + void drawImage(s16 x, s16 y, s16 startx, s16 starty, s16 width, s16 height, const u8 *image, ImageMode mode); + void drawShadow(s16 x, s16 y, s16 width, s16 height); + void drawTooltip(s16 x, s16 y, const char *text, color_t backgroundColor, color_t textColor, u8 alpha, bool flipped); + + static bool requestKeyboardInput(std::string headerText, std::string subHeaderText, std::string initialText, SwkbdType type, char *out_text, size_t maxLength); + static u128 requestPlayerSelection(); + static void requestErrorMessage(Result result); + +protected: + void beginDraw(); + void endDraw(); + +private: + FT_Error m_fontLibret, m_fontFacesRet[FONT_FACES_MAX]; + FT_Library m_fontLibrary; + FT_Face m_fontFaces[FONT_FACES_MAX]; + FT_Face m_fontLastUsedFace; + size_t m_fontFacesTotal; + + std::unordered_map> m_stringDimensions; + + void drawText_(u32 font, s16 x, s16 y, color_t clr, const char* text, s32 max_width, const char* end_text); + inline void draw4PixelsRaw(s16 x, s16 y, color_t clr); + inline bool fontLoadGlyph(glyph_t* glyph, u32 font, u32 codepoint); + void drawGlyph(s16 x, s16 y, color_t clr, const glyph_t* glyph); + bool setFontType(u32 font); + inline u8 decodeByte(const char** ptr); + inline s8 decodeUTF8Cont(const char** ptr); + inline u32 decodeUTF8(const char** ptr); + inline void drawPixel(s16 x, s16 y, color_t clr); +}; + +#define COLOR_WHITE makeColor(255, 255, 255, 255) +#define COLOR_BLACK makeColor(0, 0, 0, 255) + extern void requestDraw(); \ No newline at end of file diff --git a/include/guis/gui_about.hpp b/include/guis/gui_about.hpp index 86d9f92f..21ffba29 100644 --- a/include/guis/gui_about.hpp +++ b/include/guis/gui_about.hpp @@ -1,17 +1,17 @@ -#pragma once - -#include "guis/gui.hpp" - -#include - -class GuiAbout : public Gui { -public: - GuiAbout(); - ~GuiAbout(); - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); -}; +#pragma once + +#include "guis/gui.hpp" + +#include + +class GuiAbout : public Gui { +public: + GuiAbout(); + ~GuiAbout(); + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); +}; diff --git a/include/guis/gui_cheats.hpp b/include/guis/gui_cheats.hpp index 26a7b8c2..461f70ae 100644 --- a/include/guis/gui_cheats.hpp +++ b/include/guis/gui_cheats.hpp @@ -1,85 +1,85 @@ -#pragma once - -#include "guis/gui.hpp" -#include "types.h" - -#include -#include -#include -#include - -#include "helpers/debugger.hpp" -#include "helpers/memory_dump.hpp" - -#include "helpers/dmntcht.h" - -class GuiCheats : public Gui { - -public: - GuiCheats(); - ~GuiCheats(); - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - -private: - Debugger *m_debugger; - u8 m_ramBuffer[0x10 * 14] = { 0 }; - color_t m_memory[1024] = { 0 }; - - u8 m_selectedEntry = 0; - - searchValue_t m_searchValue[2]; - enum { FORMAT_DEC, FORMAT_HEX } m_searchValueFormat = FORMAT_DEC; - - enum { CHEATS, CANDIDATES } m_menuLocation = CHEATS; - enum { SEARCH_NONE, SEARCH_TYPE, SEARCH_MODE, SEARCH_REGION, SEARCH_VALUE } m_searchMenuLocation = SEARCH_NONE; - searchType_t m_searchType = SEARCH_TYPE_NONE; - searchMode_t m_searchMode = SEARCH_MODE_NONE; - searchRegion_t m_searchRegion = SEARCH_REGION_NONE; - - std::vector m_memoryInfo; - MemoryDump *m_memoryDump; - std::map m_frozenAddresses; - - bool m_cheatsPresent = false; - bool m_sysmodulePresent = false; - - u64 m_addressSpaceBaseAddr = 0x00; - u64 m_heapBaseAddr = 0x00; - u64 m_mainBaseAddr = 0x00; - - u64 m_heapSize = 0; - u64 m_mainSize = 0; - - u8 m_buildID[0x20]; - - DmntCheatEntry *m_cheats; - u64 m_cheatCnt; - - void drawSearchRAMMenu(); - - void searchMemoryAddressesPrimary(Debugger *debugger, searchValue_t searchValue1, - searchValue_t searchValue2, searchType_t searchType, - searchMode_t searchMode, searchRegion_t searchRegion, - MemoryDump **displayDump, std::vector memInfos); - - void searchMemoryAddressesSecondary(Debugger *debugger, searchValue_t searchValue1, - searchValue_t searchValue2, searchType_t searchType, - searchMode_t searchMode, MemoryDump **displayDump); - - void searchMemoryValuesPrimary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, - searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos); - - - void searchMemoryValuesSecondary(Debugger *debugger, searchType_t searchType, - searchMode_t searchMode, searchRegion_t searchRegion, - MemoryDump **displayDump, std::vector memInfos); - - void searchMemoryValuesTertiary(Debugger *debugger, searchType_t searchType, - searchMode_t searchMode, searchRegion_t searchRegion, - MemoryDump **displayDump, std::vector memInfos); -}; +#pragma once + +#include "guis/gui.hpp" +#include "types.h" + +#include +#include +#include +#include + +#include "helpers/debugger.hpp" +#include "helpers/memory_dump.hpp" + +#include "helpers/dmntcht.h" + +class GuiCheats : public Gui { + +public: + GuiCheats(); + ~GuiCheats(); + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + +private: + Debugger *m_debugger; + u8 m_ramBuffer[0x10 * 14] = { 0 }; + color_t m_memory[1024] = { 0 }; + + u8 m_selectedEntry = 0; + + searchValue_t m_searchValue[2]; + enum { FORMAT_DEC, FORMAT_HEX } m_searchValueFormat = FORMAT_DEC; + + enum { CHEATS, CANDIDATES } m_menuLocation = CHEATS; + enum { SEARCH_NONE, SEARCH_TYPE, SEARCH_MODE, SEARCH_REGION, SEARCH_VALUE } m_searchMenuLocation = SEARCH_NONE; + searchType_t m_searchType = SEARCH_TYPE_NONE; + searchMode_t m_searchMode = SEARCH_MODE_NONE; + searchRegion_t m_searchRegion = SEARCH_REGION_NONE; + + std::vector m_memoryInfo; + MemoryDump *m_memoryDump; + std::map m_frozenAddresses; + + bool m_cheatsPresent = false; + bool m_sysmodulePresent = false; + + u64 m_addressSpaceBaseAddr = 0x00; + u64 m_heapBaseAddr = 0x00; + u64 m_mainBaseAddr = 0x00; + + u64 m_heapSize = 0; + u64 m_mainSize = 0; + + u8 m_buildID[0x20]; + + DmntCheatEntry *m_cheats; + u64 m_cheatCnt; + + void drawSearchRAMMenu(); + + void searchMemoryAddressesPrimary(Debugger *debugger, searchValue_t searchValue1, + searchValue_t searchValue2, searchType_t searchType, + searchMode_t searchMode, searchRegion_t searchRegion, + MemoryDump **displayDump, std::vector memInfos); + + void searchMemoryAddressesSecondary(Debugger *debugger, searchValue_t searchValue1, + searchValue_t searchValue2, searchType_t searchType, + searchMode_t searchMode, MemoryDump **displayDump); + + void searchMemoryValuesPrimary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, + searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos); + + + void searchMemoryValuesSecondary(Debugger *debugger, searchType_t searchType, + searchMode_t searchMode, searchRegion_t searchRegion, + MemoryDump **displayDump, std::vector memInfos); + + void searchMemoryValuesTertiary(Debugger *debugger, searchType_t searchType, + searchMode_t searchMode, searchRegion_t searchRegion, + MemoryDump **displayDump, std::vector memInfos); +}; diff --git a/include/guis/gui_editor.hpp b/include/guis/gui_editor.hpp index fe39e2fa..84cdffff 100644 --- a/include/guis/gui_editor.hpp +++ b/include/guis/gui_editor.hpp @@ -1,52 +1,52 @@ -#pragma once - -#include "guis/gui.hpp" -#include "widgets/widget.hpp" -#include "json.hpp" - -#include - -#define CONFIG_ROOT EDIZON_DIR "/editor/" - -using json = nlohmann::json; - -typedef struct { - std::string fileName; - u8 configIndex; -} SaveFile; - -class GuiEditor : public Gui { -public: - GuiEditor(); - ~GuiEditor(); - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - - static inline std::vector g_currSaveFile; - static inline std::string g_currSaveFileName = ""; - -private: - void updateBackupList(); - std::string readMetaDataUsername(std::string path); - - WidgetItems m_widgets; - std::vector m_titleIcon; - - std::vector m_backupTitles; - std::vector m_backupFolderNames; - std::vector m_backupPaths; - std::vector m_saveFiles; - - color_t m_dominantColor; - color_t m_textColor; - - s8 m_configFileResult; - - Interpreter *m_interpreter; - - void updateSaveFileList(std::vector saveFilePath, std::string files, u8 configIndex); +#pragma once + +#include "guis/gui.hpp" +#include "widgets/widget.hpp" +#include "json.hpp" + +#include + +#define CONFIG_ROOT EDIZON_DIR "/editor/" + +using json = nlohmann::json; + +typedef struct { + std::string fileName; + u8 configIndex; +} SaveFile; + +class GuiEditor : public Gui { +public: + GuiEditor(); + ~GuiEditor(); + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + + static inline std::vector g_currSaveFile; + static inline std::string g_currSaveFileName = ""; + +private: + void updateBackupList(); + std::string readMetaDataUsername(std::string path); + + WidgetItems m_widgets; + std::vector m_titleIcon; + + std::vector m_backupTitles; + std::vector m_backupFolderNames; + std::vector m_backupPaths; + std::vector m_saveFiles; + + color_t m_dominantColor; + color_t m_textColor; + + s8 m_configFileResult; + + Interpreter *m_interpreter; + + void updateSaveFileList(std::vector saveFilePath, std::string files, u8 configIndex); }; \ No newline at end of file diff --git a/include/guis/gui_guide.hpp b/include/guis/gui_guide.hpp index aa183c66..62c76999 100644 --- a/include/guis/gui_guide.hpp +++ b/include/guis/gui_guide.hpp @@ -1,35 +1,35 @@ -#pragma once - -#include "guis/gui.hpp" - -#include -#include -#include - -#define GUIDE_PAGE_CNT 10 - -class GuiGuide : public Gui { -public: - GuiGuide(); - ~GuiGuide(); - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - -private: - static inline u16 g_selectedPage = 1; - - typedef struct { - char *data; - std::string title; - size_t length; - u16 x, y; - u16 w, h; - enum { TYPE_IMAGE, TYPE_TEXT } type; - } guide_obj_t; - - std::vector m_objects; -}; +#pragma once + +#include "guis/gui.hpp" + +#include +#include +#include + +#define GUIDE_PAGE_CNT 10 + +class GuiGuide : public Gui { +public: + GuiGuide(); + ~GuiGuide(); + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + +private: + static inline u16 g_selectedPage = 1; + + typedef struct { + char *data; + std::string title; + size_t length; + u16 x, y; + u16 w, h; + enum { TYPE_IMAGE, TYPE_TEXT } type; + } guide_obj_t; + + std::vector m_objects; +}; diff --git a/include/guis/gui_main.hpp b/include/guis/gui_main.hpp index fe7087a2..930f3b14 100644 --- a/include/guis/gui_main.hpp +++ b/include/guis/gui_main.hpp @@ -1,36 +1,36 @@ -#pragma once - -#include "guis/gui.hpp" - -#include -#include - -#define MENU_SCROLL_SPEED 40 - -class GuiMain : public Gui { -public: - GuiMain(); - ~GuiMain(); - - static inline bool g_shouldUpdate = false; - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - -private: - static inline struct { - s16 titleIndex; - s8 extraOption; - - u64 titleId; - u128 userId; - } m_selected = { 0, -1, 0, 0 }; - - static inline bool m_editableOnly = false; - bool m_backupAll = false; - - void updateEditableTitlesList(); -}; +#pragma once + +#include "guis/gui.hpp" + +#include +#include + +#define MENU_SCROLL_SPEED 40 + +class GuiMain : public Gui { +public: + GuiMain(); + ~GuiMain(); + + static inline bool g_shouldUpdate = false; + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + +private: + static inline struct { + s16 titleIndex; + s8 extraOption; + + u64 titleId; + u128 userId; + } m_selected = { 0, -1, 0, 0 }; + + static inline bool m_editableOnly = false; + bool m_backupAll = false; + + void updateEditableTitlesList(); +}; diff --git a/include/guis/gui_tx_warning.hpp b/include/guis/gui_tx_warning.hpp index 6f8e2ea1..0ff00d3e 100644 --- a/include/guis/gui_tx_warning.hpp +++ b/include/guis/gui_tx_warning.hpp @@ -1,19 +1,19 @@ -#pragma once - -#include "guis/gui.hpp" - -#include -#include -#include - -class GuiTXWarning : public Gui { -public: - GuiTXWarning(); - ~GuiTXWarning(); - - void update(); - void draw(); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); -}; +#pragma once + +#include "guis/gui.hpp" + +#include +#include +#include + +class GuiTXWarning : public Gui { +public: + GuiTXWarning(); + ~GuiTXWarning(); + + void update(); + void draw(); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); +}; diff --git a/include/helpers/account.hpp b/include/helpers/account.hpp index a4c24c9d..5cb2ebb0 100644 --- a/include/helpers/account.hpp +++ b/include/helpers/account.hpp @@ -1,34 +1,34 @@ -#pragma once - -#include - -#include -#include -#include - -class Account { -public: - static inline Account *g_currAccount = nullptr; - static inline std::unordered_map g_accounts; - - static inline u128 g_activeUser = 0; - - Account(u128 userID); - ~Account(); - - std::string getUserName(); - u128 getUserID(); - u8* getProfileImage(); - bool isInitialized(); - -private: - AccountProfile m_profile; - AccountUserData m_userData; - AccountProfileBase m_profileBase; - - u128 m_userID; - std::vector m_profileImage; - size_t m_profileImageSize; - std::string m_userName; - bool m_isInitialized; -}; +#pragma once + +#include + +#include +#include +#include + +class Account { +public: + static inline Account *g_currAccount = nullptr; + static inline std::unordered_map g_accounts; + + static inline u128 g_activeUser = 0; + + Account(u128 userID); + ~Account(); + + std::string getUserName(); + u128 getUserID(); + u8* getProfileImage(); + bool isInitialized(); + +private: + AccountProfile m_profile; + AccountUserData m_userData; + AccountProfileBase m_profileBase; + + u128 m_userID; + std::vector m_profileImage; + size_t m_profileImageSize; + std::string m_userName; + bool m_isInitialized; +}; diff --git a/include/helpers/config.hpp b/include/helpers/config.hpp index 34081124..26a5e8b5 100644 --- a/include/helpers/config.hpp +++ b/include/helpers/config.hpp @@ -1,20 +1,20 @@ -#pragma once - -#include -#include -#include -#include - -#define CONFIG_PATH EDIZON_DIR "/config.dat" - -namespace Config { - typedef struct ConfigData { - char magic[8]; - bool hideSX; - char latestCommit[40]; - } config_data_t; - - void readConfig(); - void writeConfig(); - config_data_t* getConfig(); +#pragma once + +#include +#include +#include +#include + +#define CONFIG_PATH EDIZON_DIR "/config.dat" + +namespace Config { + typedef struct ConfigData { + char magic[8]; + bool hideSX; + char latestCommit[40]; + } config_data_t; + + void readConfig(); + void writeConfig(); + config_data_t* getConfig(); } \ No newline at end of file diff --git a/include/helpers/debugger.hpp b/include/helpers/debugger.hpp index e1ad8210..f55410de 100644 --- a/include/helpers/debugger.hpp +++ b/include/helpers/debugger.hpp @@ -1,25 +1,25 @@ -#pragma once - -#include - -class Debugger { - -public: - Debugger(); - ~Debugger(); - - Result attachToProcess(); - - u64 getRunningApplicationTID(); - u64 getRunningApplicationPID(); - - u64 peekMemory(u64 address); - void pokeMemory(size_t varSize, u64 address, u64 value); - MemoryInfo queryMemory(u64 address); - void readMemory(void *buffer, size_t bufferSize, u64 address); - void writeMemory(void *buffer, size_t bufferSize, u64 address); - -private: - Handle m_debugHandle; - u64 m_tid = 0, m_pid = 0; +#pragma once + +#include + +class Debugger { + +public: + Debugger(); + ~Debugger(); + + Result attachToProcess(); + + u64 getRunningApplicationTID(); + u64 getRunningApplicationPID(); + + u64 peekMemory(u64 address); + void pokeMemory(size_t varSize, u64 address, u64 value); + MemoryInfo queryMemory(u64 address); + void readMemory(void *buffer, size_t bufferSize, u64 address); + void writeMemory(void *buffer, size_t bufferSize, u64 address); + +private: + Handle m_debugHandle; + u64 m_tid = 0, m_pid = 0; }; \ No newline at end of file diff --git a/include/helpers/dmntcht.h b/include/helpers/dmntcht.h index c7e873f7..b7ef24a6 100644 --- a/include/helpers/dmntcht.h +++ b/include/helpers/dmntcht.h @@ -1,76 +1,76 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - u64 base; - u64 size; -} DmntMemoryRegionExtents; - -typedef struct { - u64 process_id; - u64 title_id; - DmntMemoryRegionExtents main_nso_extents; - DmntMemoryRegionExtents heap_extents; - DmntMemoryRegionExtents alias_extents; - DmntMemoryRegionExtents address_space_extents; - u8 main_nso_build_id[0x20]; -} DmntCheatProcessMetadata; - -typedef struct { - char readable_name[0x40]; - uint32_t num_opcodes; - uint32_t opcodes[0x100]; -} DmntCheatDefinition; - -typedef struct { - bool enabled; - uint32_t cheat_id; - DmntCheatDefinition definition; -} DmntCheatEntry; - -typedef struct { - u64 value; - u8 width; -} DmntFrozenAddressValue; - -typedef struct { - u64 address; - DmntFrozenAddressValue value; -} DmntFrozenAddressEntry; - -Result dmntchtInitialize(void); -void dmntchtExit(void); -Service* dmntchtGetServiceSession(void); - -Result dmntchtHasCheatProcess(bool *out); -Result dmntchtGetCheatProcessEvent(Event *event); -Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata); -Result dmntchtForceOpenCheatProcess(void); - -Result dmntchtGetCheatProcessMappingCount(u64 *out_count); -Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size); -Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size); -Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address); - -Result dmntchtGetCheatCount(u64 *out_count); -Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id); -Result dmntchtToggleCheat(u32 cheat_id); -Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id); -Result dmntchtRemoveCheat(u32 cheat_id); - -Result dmntchtGetFrozenAddressCount(u64 *out_count); -Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address); -Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value); -Result dmntchtDisableFrozenAddress(u64 address); - -#ifdef __cplusplus -} +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + u64 base; + u64 size; +} DmntMemoryRegionExtents; + +typedef struct { + u64 process_id; + u64 title_id; + DmntMemoryRegionExtents main_nso_extents; + DmntMemoryRegionExtents heap_extents; + DmntMemoryRegionExtents alias_extents; + DmntMemoryRegionExtents address_space_extents; + u8 main_nso_build_id[0x20]; +} DmntCheatProcessMetadata; + +typedef struct { + char readable_name[0x40]; + uint32_t num_opcodes; + uint32_t opcodes[0x100]; +} DmntCheatDefinition; + +typedef struct { + bool enabled; + uint32_t cheat_id; + DmntCheatDefinition definition; +} DmntCheatEntry; + +typedef struct { + u64 value; + u8 width; +} DmntFrozenAddressValue; + +typedef struct { + u64 address; + DmntFrozenAddressValue value; +} DmntFrozenAddressEntry; + +Result dmntchtInitialize(void); +void dmntchtExit(void); +Service* dmntchtGetServiceSession(void); + +Result dmntchtHasCheatProcess(bool *out); +Result dmntchtGetCheatProcessEvent(Event *event); +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata); +Result dmntchtForceOpenCheatProcess(void); + +Result dmntchtGetCheatProcessMappingCount(u64 *out_count); +Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size); +Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size); +Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address); + +Result dmntchtGetCheatCount(u64 *out_count); +Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id); +Result dmntchtToggleCheat(u32 cheat_id); +Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id); +Result dmntchtRemoveCheat(u32 cheat_id); + +Result dmntchtGetFrozenAddressCount(u64 *out_count); +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count); +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address); +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value); +Result dmntchtDisableFrozenAddress(u64 address); + +#ifdef __cplusplus +} #endif \ No newline at end of file diff --git a/include/helpers/editor_config_parser.hpp b/include/helpers/editor_config_parser.hpp index d5d49fbc..7ec3fbd6 100644 --- a/include/helpers/editor_config_parser.hpp +++ b/include/helpers/editor_config_parser.hpp @@ -1,45 +1,45 @@ -#pragma once - -#include -#include -#include - -#include "scripting/interpreter.hpp" - -#include "widgets/widget.hpp" -#include "types.h" -#include "json.hpp" - -using json = nlohmann::json; - -#define CONFIG_ROOT EDIZON_DIR "/editor/" - -class Interpreter; - -class EditorConfigParser { -public: - EditorConfigParser() = delete; - - static s8 hasConfig(u64 titleId); - static s8 loadConfigFile(u64 titleId, std::string filepath, Interpreter **interpreter); - static void unloadConfigFile(); - static void createWidgets(WidgetItems &widgets, Interpreter &interpreter, u8 configIndex); - - static inline std::unordered_map g_editableTitles; - static inline std::unordered_map g_betaTitles; - static inline std::string g_currConfigAuthor = ""; - - template - static inline T getOptionalValue(json j, std::string key, T elseVal) { - return j.find(key) != j.end() ? j[key].get() : elseVal; - } - - static inline json& getConfigFile() { - return m_configFile; - } - -private: - static inline json m_configFile; - static inline u8 m_useInsteadTries; - -}; +#pragma once + +#include +#include +#include + +#include "scripting/interpreter.hpp" + +#include "widgets/widget.hpp" +#include "types.h" +#include "json.hpp" + +using json = nlohmann::json; + +#define CONFIG_ROOT EDIZON_DIR "/editor/" + +class Interpreter; + +class EditorConfigParser { +public: + EditorConfigParser() = delete; + + static s8 hasConfig(u64 titleId); + static s8 loadConfigFile(u64 titleId, std::string filepath, Interpreter **interpreter); + static void unloadConfigFile(); + static void createWidgets(WidgetItems &widgets, Interpreter &interpreter, u8 configIndex); + + static inline std::unordered_map g_editableTitles; + static inline std::unordered_map g_betaTitles; + static inline std::string g_currConfigAuthor = ""; + + template + static inline T getOptionalValue(json j, std::string key, T elseVal) { + return j.find(key) != j.end() ? j[key].get() : elseVal; + } + + static inline json& getConfigFile() { + return m_configFile; + } + +private: + static inline json m_configFile; + static inline u8 m_useInsteadTries; + +}; diff --git a/include/helpers/encoding.hpp b/include/helpers/encoding.hpp index e6034a99..893592ee 100644 --- a/include/helpers/encoding.hpp +++ b/include/helpers/encoding.hpp @@ -1,14 +1,14 @@ -#pragma once - -#include - -#include - -namespace Encoding { - - std::vector uft16leToUtf8(u8 *data, size_t length); - std::vector uft16beToUtf8(u8 *data, size_t length); - std::vector utf8ToUtf16le(u8 *data, size_t length); - std::vector utf8ToUtf16be(u8 *data, size_t length); - -} +#pragma once + +#include + +#include + +namespace Encoding { + + std::vector uft16leToUtf8(u8 *data, size_t length); + std::vector uft16beToUtf8(u8 *data, size_t length); + std::vector utf8ToUtf16le(u8 *data, size_t length); + std::vector utf8ToUtf16be(u8 *data, size_t length); + +} diff --git a/include/helpers/memory_dump.hpp b/include/helpers/memory_dump.hpp index b3f1db33..6e7e562a 100644 --- a/include/helpers/memory_dump.hpp +++ b/include/helpers/memory_dump.hpp @@ -1,37 +1,37 @@ -#pragma once - -#include "types.h" - -#include -#include - -class MemoryDump { -public: - MemoryDump(std::string filePath, DumpType dumpType, bool discardFile); - ~MemoryDump(); - - void setBaseAddresses(u64 addrSpaceBase, u64 heapBase, u64 mainBase, u64 heapSize, u64 mainSize); - void setSearchParams(searchType_t searchDataType, searchMode_t searchMode, searchRegion_t searchRegion, searchValue_t searchValue1, searchValue_t searchValue2); - - void addData(u8 *buffer, size_t bufferSize); - size_t size(); - void clear(); - - int getData(u64 addr, void *buffer, size_t bufferSize); - u8 operator[](u64 index); - - data_header_t getDumpInfo(); - - void setDumpType(enum DumpType dumpType); - void flushBuffer(); - -private: - FILE *m_dumpFile; - std::string m_filePath; - std::vector m_data; - - data_header_t m_dataHeader; - - bool isFileOpen(); - void writeHeader(); +#pragma once + +#include "types.h" + +#include +#include + +class MemoryDump { +public: + MemoryDump(std::string filePath, DumpType dumpType, bool discardFile); + ~MemoryDump(); + + void setBaseAddresses(u64 addrSpaceBase, u64 heapBase, u64 mainBase, u64 heapSize, u64 mainSize); + void setSearchParams(searchType_t searchDataType, searchMode_t searchMode, searchRegion_t searchRegion, searchValue_t searchValue1, searchValue_t searchValue2); + + void addData(u8 *buffer, size_t bufferSize); + size_t size(); + void clear(); + + int getData(u64 addr, void *buffer, size_t bufferSize); + u8 operator[](u64 index); + + data_header_t getDumpInfo(); + + void setDumpType(enum DumpType dumpType); + void flushBuffer(); + +private: + FILE *m_dumpFile; + std::string m_filePath; + std::vector m_data; + + data_header_t m_dataHeader; + + bool isFileOpen(); + void writeHeader(); }; \ No newline at end of file diff --git a/include/helpers/save.hpp b/include/helpers/save.hpp index 2e6622a2..d393f87f 100644 --- a/include/helpers/save.hpp +++ b/include/helpers/save.hpp @@ -1,31 +1,31 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "json.hpp" - -#define SAVE_DEV "save" - -Result _getSaveList(std::vector &saveInfoList); - -s32 deleteDirRecursively(const char *path, bool isSave); -void makeExInjDir(char ptr[0x100], u64 titleID, u128 userID, bool isInject); -Result mountSaveByTitleAccountIDs(const u64 titleID, const u128 userID, FsFileSystem& tmpfs); -s32 isDirectory(const char *path); -s32 cpFile(std::string srcPath, std::string dstPath); -s32 copyAllSave(const char * path, bool isInject, const char exInjDir[0x100]); - -s32 backupSave(u64 titleID, u128 userID, bool isBatch, std::string backupName); -s32 restoreSave(u64 titleID, u128 userID, const char* path); - -s32 loadSaveFile(std::vector *buffer, size_t *length, u64 titleID, u128 userID, const char *path); -s32 storeSaveFile(u8 *buffer, size_t length, u64 titleID, u128 userID, const char *path); +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "json.hpp" + +#define SAVE_DEV "save" + +Result _getSaveList(std::vector &saveInfoList); + +s32 deleteDirRecursively(const char *path, bool isSave); +void makeExInjDir(char ptr[0x100], u64 titleID, u128 userID, bool isInject); +Result mountSaveByTitleAccountIDs(const u64 titleID, const u128 userID, FsFileSystem& tmpfs); +s32 isDirectory(const char *path); +s32 cpFile(std::string srcPath, std::string dstPath); +s32 copyAllSave(const char * path, bool isInject, const char exInjDir[0x100]); + +s32 backupSave(u64 titleID, u128 userID, bool isBatch, std::string backupName); +s32 restoreSave(u64 titleID, u128 userID, const char* path); + +s32 loadSaveFile(std::vector *buffer, size_t *length, u64 titleID, u128 userID, const char *path); +s32 storeSaveFile(u8 *buffer, size_t length, u64 titleID, u128 userID, const char *path); diff --git a/include/helpers/title.hpp b/include/helpers/title.hpp index 69642d90..ef999772 100644 --- a/include/helpers/title.hpp +++ b/include/helpers/title.hpp @@ -1,38 +1,38 @@ -#pragma once - -#include -#include -#include -#include - -#include "types.h" -#include "helpers/save.hpp" -#include "helpers/account.hpp" - -class Title { -public: - static inline Title *g_currTitle; - static inline std::map g_titles; - - static inline u64 g_activeTitle = 0; - - Title(FsSaveDataInfo& saveInfo); - ~Title(); - - std::string getTitleName(); - std::string getTitleAuthor(); - std::string getTitleVersion(); - u8* getTitleIcon(); - std::vector getUserIDs(); - void addUserID(u128 userID); - u64 getTitleID(); - -private: - u8 m_titleIcon[256*256*3]; - u64 m_titleID; - std::string m_titleName; - std::string m_titleAuthor; - std::string m_titleVersion; - std::vector m_userIDs; - u8 m_errorCode; -}; +#pragma once + +#include +#include +#include +#include + +#include "types.h" +#include "helpers/save.hpp" +#include "helpers/account.hpp" + +class Title { +public: + static inline Title *g_currTitle; + static inline std::map g_titles; + + static inline u64 g_activeTitle = 0; + + Title(FsSaveDataInfo& saveInfo); + ~Title(); + + std::string getTitleName(); + std::string getTitleAuthor(); + std::string getTitleVersion(); + u8* getTitleIcon(); + std::vector getUserIDs(); + void addUserID(u128 userID); + u64 getTitleID(); + +private: + u8 m_titleIcon[256*256*3]; + u64 m_titleID; + std::string m_titleName; + std::string m_titleAuthor; + std::string m_titleVersion; + std::vector m_userIDs; + u8 m_errorCode; +}; diff --git a/include/helpers/util.h b/include/helpers/util.h index 60f18949..87f03b45 100644 --- a/include/helpers/util.h +++ b/include/helpers/util.h @@ -1,26 +1,26 @@ -#pragma once -#include - -#define DEBUG_LOG(statement, formatStr) (printf("%s : %d %s -> " formatStr "\n", __FUNCTION__, __LINE__, #statement, statement)) - -#ifdef __cplusplus -extern "C" { -#endif - -Result amspmdmntInitialize(void); -void amspmdmntExit(void); - -Result amspmdmntAtmosphereGetProcessHandle(Handle *out_processHandle); - -bool isServiceRunning(const char *serviceName); -void getCurrTimeString(char *buffer); -void getCurrBatteryPercentage(char *buffer); - -void ledInit(); -void setLedState(bool state); - -void overclockSystem(bool enable); - -#ifdef __cplusplus -} +#pragma once +#include + +#define DEBUG_LOG(statement, formatStr) (printf("%s : %d %s -> " formatStr "\n", __FUNCTION__, __LINE__, #statement, statement)) + +#ifdef __cplusplus +extern "C" { +#endif + +Result amspmdmntInitialize(void); +void amspmdmntExit(void); + +Result amspmdmntAtmosphereGetProcessHandle(Handle *out_processHandle); + +bool isServiceRunning(const char *serviceName); +void getCurrTimeString(char *buffer); +void getCurrBatteryPercentage(char *buffer); + +void ledInit(); +void setLedState(bool state); + +void overclockSystem(bool enable); + +#ifdef __cplusplus +} #endif \ No newline at end of file diff --git a/include/scripting/interpreter.hpp b/include/scripting/interpreter.hpp index 4830da66..3bf22f87 100644 --- a/include/scripting/interpreter.hpp +++ b/include/scripting/interpreter.hpp @@ -1,50 +1,50 @@ -#pragma once - -#include -#include - -#include - -class Interpreter { -public: - Interpreter(); - virtual ~Interpreter(); - - virtual bool initialize(std::string filetype) = 0; - virtual void deinitialize() = 0; - - virtual s64 getValueFromSaveFile() = 0; - virtual std::string getStringFromSaveFile() = 0; - - virtual void setValueInSaveFile(s64 value) = 0; - virtual void setStringInSaveFile(std::string value) = 0; - - virtual void getModifiedSaveFile(std::vector &buffer) = 0; - - virtual s64 getDummyValue() = 0; - virtual std::string getDummyString() = 0; - virtual void setDummyValue(s64 value) = 0; - virtual void setDummyString(std::string value) = 0; - - virtual std::string callFunction(std::string funcName) = 0; - - void setArgs(std::vector intArgs, std::vector strArgs); - void setSaveFileBuffer(u8 *buffer, size_t bufferSize, std::string encoding); - - double evaluateEquation(std::string equation, s64 value); - -protected: - std::string m_filetype; - std::vector m_buffer; - u64 m_bufferSize; - - std::vector m_intArgs; - std::vector m_strArgs; - - enum { - ASCII, - UTF_8, - UTF_16LE, - UTF_16BE - } m_encoding = ASCII; -}; +#pragma once + +#include +#include + +#include + +class Interpreter { +public: + Interpreter(); + virtual ~Interpreter(); + + virtual bool initialize(std::string filetype) = 0; + virtual void deinitialize() = 0; + + virtual s64 getValueFromSaveFile() = 0; + virtual std::string getStringFromSaveFile() = 0; + + virtual void setValueInSaveFile(s64 value) = 0; + virtual void setStringInSaveFile(std::string value) = 0; + + virtual void getModifiedSaveFile(std::vector &buffer) = 0; + + virtual s64 getDummyValue() = 0; + virtual std::string getDummyString() = 0; + virtual void setDummyValue(s64 value) = 0; + virtual void setDummyString(std::string value) = 0; + + virtual std::string callFunction(std::string funcName) = 0; + + void setArgs(std::vector intArgs, std::vector strArgs); + void setSaveFileBuffer(u8 *buffer, size_t bufferSize, std::string encoding); + + double evaluateEquation(std::string equation, s64 value); + +protected: + std::string m_filetype; + std::vector m_buffer; + u64 m_bufferSize; + + std::vector m_intArgs; + std::vector m_strArgs; + + enum { + ASCII, + UTF_8, + UTF_16LE, + UTF_16BE + } m_encoding = ASCII; +}; diff --git a/include/scripting/lua_interpreter.hpp b/include/scripting/lua_interpreter.hpp index db626988..dd35cb16 100644 --- a/include/scripting/lua_interpreter.hpp +++ b/include/scripting/lua_interpreter.hpp @@ -1,55 +1,55 @@ -#pragma once - -#define LLONG_MAX INT64_MAX -#define LLONG_MIN INT64_MIN -#include "lua.hpp" - -#include "interpreter.hpp" - -#include -#include - -#include - -class LuaInterpreter : public Interpreter{ -public: - LuaInterpreter(); - ~LuaInterpreter(); - - bool initialize(std::string filetype); - void deinitialize(); - - s64 getValueFromSaveFile(); - std::string getStringFromSaveFile(); - - void setValueInSaveFile(s64 value); - void setStringInSaveFile(std::string value); - - void getModifiedSaveFile(std::vector &buffer); - - s64 getDummyValue(); - std::string getDummyString(); - void setDummyValue(s64 value); - void setDummyString(std::string value); - - std::string callFunction(std::string funcName); - - int lua_getSaveFileBuffer(lua_State *state); - int lua_getSaveFileString(lua_State *state); - int lua_getStrArgs(lua_State *state); - int lua_getIntArgs(lua_State *state); - -private: - std::string m_filetype; - - lua_State *m_luaState; - - enum { - ASCII, - UTF_8, - UTF_16LE, - UTF_16BE - } m_encoding = ASCII; - - static void printError(lua_State *luaState); -}; +#pragma once + +#define LLONG_MAX INT64_MAX +#define LLONG_MIN INT64_MIN +#include "lua.hpp" + +#include "interpreter.hpp" + +#include +#include + +#include + +class LuaInterpreter : public Interpreter{ +public: + LuaInterpreter(); + ~LuaInterpreter(); + + bool initialize(std::string filetype); + void deinitialize(); + + s64 getValueFromSaveFile(); + std::string getStringFromSaveFile(); + + void setValueInSaveFile(s64 value); + void setStringInSaveFile(std::string value); + + void getModifiedSaveFile(std::vector &buffer); + + s64 getDummyValue(); + std::string getDummyString(); + void setDummyValue(s64 value); + void setDummyString(std::string value); + + std::string callFunction(std::string funcName); + + int lua_getSaveFileBuffer(lua_State *state); + int lua_getSaveFileString(lua_State *state); + int lua_getStrArgs(lua_State *state); + int lua_getIntArgs(lua_State *state); + +private: + std::string m_filetype; + + lua_State *m_luaState; + + enum { + ASCII, + UTF_8, + UTF_16LE, + UTF_16BE + } m_encoding = ASCII; + + static void printError(lua_State *luaState); +}; diff --git a/include/scripting/python_interpreter.hpp b/include/scripting/python_interpreter.hpp index cc76fb43..f60af994 100644 --- a/include/scripting/python_interpreter.hpp +++ b/include/scripting/python_interpreter.hpp @@ -1,53 +1,53 @@ -#pragma once - -#include "Python.h" - -#include "interpreter.hpp" - -#include -#include - -#include - -class PythonInterpreter : public Interpreter{ -public: - PythonInterpreter(); - ~PythonInterpreter(); - - bool initialize(std::string filetype); - void deinitialize(); - - s64 getValueFromSaveFile(); - std::string getStringFromSaveFile(); - - void setValueInSaveFile(s64 value); - void setStringInSaveFile(std::string value); - - void getModifiedSaveFile(std::vector &buffer); - - s64 getDummyValue(); - std::string getDummyString(); - void setDummyValue(s64 value); - void setDummyString(std::string value); - - std::string callFunction(std::string funcName); - - PyObject *py_getSaveFileBuffer(PyObject *self, PyObject *args); - PyObject *py_getSaveFileString(PyObject *self, PyObject *args); - PyObject *py_getStrArgs(PyObject *self, PyObject *args); - PyObject *py_getIntArgs(PyObject *self, PyObject *args); - - -private: - std::string m_filetype; - - PyObject *m_mainObject; - PyObject m_globals, m_locals; - - enum { - ASCII, - UTF_8, - UTF_16LE, - UTF_16BE - } m_encoding = ASCII; -}; +#pragma once + +#include "Python.h" + +#include "interpreter.hpp" + +#include +#include + +#include + +class PythonInterpreter : public Interpreter{ +public: + PythonInterpreter(); + ~PythonInterpreter(); + + bool initialize(std::string filetype); + void deinitialize(); + + s64 getValueFromSaveFile(); + std::string getStringFromSaveFile(); + + void setValueInSaveFile(s64 value); + void setStringInSaveFile(std::string value); + + void getModifiedSaveFile(std::vector &buffer); + + s64 getDummyValue(); + std::string getDummyString(); + void setDummyValue(s64 value); + void setDummyString(std::string value); + + std::string callFunction(std::string funcName); + + PyObject *py_getSaveFileBuffer(PyObject *self, PyObject *args); + PyObject *py_getSaveFileString(PyObject *self, PyObject *args); + PyObject *py_getStrArgs(PyObject *self, PyObject *args); + PyObject *py_getIntArgs(PyObject *self, PyObject *args); + + +private: + std::string m_filetype; + + PyObject *m_mainObject; + PyObject m_globals, m_locals; + + enum { + ASCII, + UTF_8, + UTF_16LE, + UTF_16BE + } m_encoding = ASCII; +}; diff --git a/include/theme.h b/include/theme.h index aece89af..62d9dac4 100644 --- a/include/theme.h +++ b/include/theme.h @@ -1,26 +1,26 @@ -#pragma once - -#include -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif -typedef struct { - color_t textColor; - color_t backgroundColor; - color_t highlightColor; - color_t selectedColor; - color_t separatorColor; - color_t selectedButtonColor; - color_t tooltipColor; - color_t tooltipTextColor; -} theme_t; - -extern theme_t currTheme; - -void setTheme(ColorSetId colorSetId); - -#ifdef __cplusplus -} +#pragma once + +#include +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct { + color_t textColor; + color_t backgroundColor; + color_t highlightColor; + color_t selectedColor; + color_t separatorColor; + color_t selectedButtonColor; + color_t tooltipColor; + color_t tooltipTextColor; +} theme_t; + +extern theme_t currTheme; + +void setTheme(ColorSetId colorSetId); + +#ifdef __cplusplus +} #endif \ No newline at end of file diff --git a/include/types.h b/include/types.h index 1da7aa0c..3dd59cba 100644 --- a/include/types.h +++ b/include/types.h @@ -1,131 +1,131 @@ -#pragma once - -#include - -typedef union { - u32 color_abgr; - - struct { - u8 r, g, b, a; - }; - -} color_t; - -typedef enum { - IMAGE_MODE_RGB24, - IMAGE_MODE_RGBA32, - IMAGE_MODE_BGR24, - IMAGE_MODE_ABGR32 -} ImageMode; - -typedef enum { - ALIGNED_LEFT, - ALIGNED_CENTER, - ALIGNED_RIGHT -} TextAlignment; - -typedef struct { - u8 magic[4]; // 'fFNT' - int version; // 1 - u16 npages; - u8 height; - u8 baseline; -} ffnt_header_t; - -typedef struct { - u32 size, offset; -} ffnt_pageentry_t; - -typedef struct { - u32 pos[0x100]; - u8 widths[0x100]; - u8 heights[0x100]; - s8 advances[0x100]; - s8 posX[0x100]; - s8 posY[0x100]; -} ffnt_pagehdr_t; - -typedef struct { - ffnt_pagehdr_t hdr; - u8 data[]; -} ffnt_page_t; - -typedef struct { - u8 width, height; - s8 posX, posY, advance, pitch; - const u8* data; -} glyph_t; - -typedef struct{ - u64 addr; - u8 type; -} PACKED ramAddr_t; - - typedef union { - u8 _u8; - s8 _s8; - u16 _u16; - s16 _s16; - u32 _u32; - s32 _s32; - u64 _u64; - s64 _s64; - float _f32; - double _f64; -} searchValue_t; - -typedef enum { - SEARCH_TYPE_NONE = -1, - SEARCH_TYPE_UNSIGNED_8BIT, - SEARCH_TYPE_SIGNED_8BIT, - SEARCH_TYPE_UNSIGNED_16BIT, - SEARCH_TYPE_SIGNED_16BIT, - SEARCH_TYPE_UNSIGNED_32BIT, - SEARCH_TYPE_SIGNED_32BIT, - SEARCH_TYPE_UNSIGNED_64BIT, - SEARCH_TYPE_SIGNED_64BIT, - SEARCH_TYPE_FLOAT_32BIT, - SEARCH_TYPE_FLOAT_64BIT, - SEARCH_TYPE_POINTER -} searchType_t; - -typedef enum { - SEARCH_MODE_NONE = -1, - SEARCH_MODE_EQ, - SEARCH_MODE_NEQ, - SEARCH_MODE_GT, - SEARCH_MODE_GTE, - SEARCH_MODE_LT, - SEARCH_MODE_LTE, - SEARCH_MODE_RANGE, - SEARCH_MODE_SAME, - SEARCH_MODE_DIFF, - SEARCH_MODE_INC, - SEARCH_MODE_DEC -} searchMode_t; - -typedef enum { - SEARCH_REGION_NONE = -1, - SEARCH_REGION_HEAP, - SEARCH_REGION_MAIN, - SEARCH_REGION_HEAP_AND_MAIN, - SEARCH_REGION_RAM -} searchRegion_t; - -typedef enum DumpType { UNDEFINED = '-', ADDR = 'A', DATA = 'D' } DumpType; - -typedef struct DataHeader { - u32 magic; // EDZN 0x4E5A4445 (Reversed for LE) - char dumpType; // '-' (0x2D) for not set yet, 'A' (0x41) for addresses, 'D' (0x44) for data - u32 dataSize; // Size of data - searchType_t searchDataType; - searchMode_t searchMode; - searchRegion_t searchRegion; - searchValue_t searchValue[2]; - u64 heapBaseAddress; - u64 heapSize; - u64 mainBaseAddress; - u64 mainSize; - u64 addrSpaceBaseAddress; - u8 endOfHeader; // '@' - Signals the end of the header +#pragma once + +#include + +typedef union { + u32 color_abgr; + + struct { + u8 r, g, b, a; + }; + +} color_t; + +typedef enum { + IMAGE_MODE_RGB24, + IMAGE_MODE_RGBA32, + IMAGE_MODE_BGR24, + IMAGE_MODE_ABGR32 +} ImageMode; + +typedef enum { + ALIGNED_LEFT, + ALIGNED_CENTER, + ALIGNED_RIGHT +} TextAlignment; + +typedef struct { + u8 magic[4]; // 'fFNT' + int version; // 1 + u16 npages; + u8 height; + u8 baseline; +} ffnt_header_t; + +typedef struct { + u32 size, offset; +} ffnt_pageentry_t; + +typedef struct { + u32 pos[0x100]; + u8 widths[0x100]; + u8 heights[0x100]; + s8 advances[0x100]; + s8 posX[0x100]; + s8 posY[0x100]; +} ffnt_pagehdr_t; + +typedef struct { + ffnt_pagehdr_t hdr; + u8 data[]; +} ffnt_page_t; + +typedef struct { + u8 width, height; + s8 posX, posY, advance, pitch; + const u8* data; +} glyph_t; + +typedef struct{ + u64 addr; + u8 type; +} PACKED ramAddr_t; + + typedef union { + u8 _u8; + s8 _s8; + u16 _u16; + s16 _s16; + u32 _u32; + s32 _s32; + u64 _u64; + s64 _s64; + float _f32; + double _f64; +} searchValue_t; + +typedef enum { + SEARCH_TYPE_NONE = -1, + SEARCH_TYPE_UNSIGNED_8BIT, + SEARCH_TYPE_SIGNED_8BIT, + SEARCH_TYPE_UNSIGNED_16BIT, + SEARCH_TYPE_SIGNED_16BIT, + SEARCH_TYPE_UNSIGNED_32BIT, + SEARCH_TYPE_SIGNED_32BIT, + SEARCH_TYPE_UNSIGNED_64BIT, + SEARCH_TYPE_SIGNED_64BIT, + SEARCH_TYPE_FLOAT_32BIT, + SEARCH_TYPE_FLOAT_64BIT, + SEARCH_TYPE_POINTER +} searchType_t; + +typedef enum { + SEARCH_MODE_NONE = -1, + SEARCH_MODE_EQ, + SEARCH_MODE_NEQ, + SEARCH_MODE_GT, + SEARCH_MODE_GTE, + SEARCH_MODE_LT, + SEARCH_MODE_LTE, + SEARCH_MODE_RANGE, + SEARCH_MODE_SAME, + SEARCH_MODE_DIFF, + SEARCH_MODE_INC, + SEARCH_MODE_DEC +} searchMode_t; + +typedef enum { + SEARCH_REGION_NONE = -1, + SEARCH_REGION_HEAP, + SEARCH_REGION_MAIN, + SEARCH_REGION_HEAP_AND_MAIN, + SEARCH_REGION_RAM +} searchRegion_t; + +typedef enum DumpType { UNDEFINED = '-', ADDR = 'A', DATA = 'D' } DumpType; + +typedef struct DataHeader { + u32 magic; // EDZN 0x4E5A4445 (Reversed for LE) + char dumpType; // '-' (0x2D) for not set yet, 'A' (0x41) for addresses, 'D' (0x44) for data + u32 dataSize; // Size of data + searchType_t searchDataType; + searchMode_t searchMode; + searchRegion_t searchRegion; + searchValue_t searchValue[2]; + u64 heapBaseAddress; + u64 heapSize; + u64 mainBaseAddress; + u64 mainSize; + u64 addrSpaceBaseAddress; + u8 endOfHeader; // '@' - Signals the end of the header } __attribute__((packed)) data_header_t; \ No newline at end of file diff --git a/include/ui_elements/button.hpp b/include/ui_elements/button.hpp index f10f4655..cc2caa34 100644 --- a/include/ui_elements/button.hpp +++ b/include/ui_elements/button.hpp @@ -1,34 +1,34 @@ -#pragma once - -#include - -#include - -#include "guis/gui.hpp" - -class Button; -typedef struct { - std::vector buttons; - s8 selectedButton; -} buttonGroup_t; - -class Button { -public: - Button(u16 x, u16 y, u16 w, u16 h, std::string text, buttonGroup_t *buttonGroup); - ~Button(); - - void draw(Gui *gui); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - - Button* setInputAction(std::function inputActions); - -private: - u16 m_x, m_y, m_w, m_h; - std::string m_text; - buttonGroup_t *m_buttonGroup; - - std::function m_inputActions; -}; - - +#pragma once + +#include + +#include + +#include "guis/gui.hpp" + +class Button; +typedef struct { + std::vector buttons; + s8 selectedButton; +} buttonGroup_t; + +class Button { +public: + Button(u16 x, u16 y, u16 w, u16 h, std::string text, buttonGroup_t *buttonGroup); + ~Button(); + + void draw(Gui *gui); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + + Button* setInputAction(std::function inputActions); + +private: + u16 m_x, m_y, m_w, m_h; + std::string m_text; + buttonGroup_t *m_buttonGroup; + + std::function m_inputActions; +}; + + diff --git a/include/ui_elements/list_selector.hpp b/include/ui_elements/list_selector.hpp index 7fe8e0d4..56617b48 100644 --- a/include/ui_elements/list_selector.hpp +++ b/include/ui_elements/list_selector.hpp @@ -1,38 +1,38 @@ -#pragma once - -#include -#include -#include - -#include - -class Gui; - -class ListSelector { -public: - ListSelector(std::string title, std::string options, std::vector &listItems); - ~ListSelector(); - - ListSelector* setInputAction(std::function inputActions); - - void update(); - void draw(Gui *gui); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - - void show(); - void hide(); - - u16 selectedItem; - -private: - std::string m_title, m_options; - std::vector &m_listItems; - std::function m_inputActions; - - u32 m_optionsWidth, m_optionsHeight; - bool m_isShown; - s16 yOffset, yOffsetNext; - s16 startYOffset, startYOffsetNext; -}; +#pragma once + +#include +#include +#include + +#include + +class Gui; + +class ListSelector { +public: + ListSelector(std::string title, std::string options, std::vector &listItems); + ~ListSelector(); + + ListSelector* setInputAction(std::function inputActions); + + void update(); + void draw(Gui *gui); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + + void show(); + void hide(); + + u16 selectedItem; + +private: + std::string m_title, m_options; + std::vector &m_listItems; + std::function m_inputActions; + + u32 m_optionsWidth, m_optionsHeight; + bool m_isShown; + s16 yOffset, yOffsetNext; + s16 startYOffset, startYOffsetNext; +}; diff --git a/include/ui_elements/message_box.hpp b/include/ui_elements/message_box.hpp index 1b127321..7f06deba 100644 --- a/include/ui_elements/message_box.hpp +++ b/include/ui_elements/message_box.hpp @@ -1,41 +1,41 @@ -#pragma once - -#include -#include -#include - -class Gui; - -class MessageBox { -public: - typedef enum { - NONE = 0, - OKAY = 1, - YES_NO = 2 - } MessageBoxOptions; - - MessageBox(std::string message, MessageBox::MessageBoxOptions options); - ~MessageBox(); - - MessageBox* setSelectionAction(std::function selectionAction); - MessageBox* setCustomDraw(std::function customDraw); - - void draw(Gui *gui); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); - - void setProgress(s8 progress); - - void show(); - void hide(); - -private: - std::string m_message; - MessageBoxOptions m_options; - - u8 m_selectedOption; - s8 m_progress; - std::function m_selectionAction; - std::function m_customDraw; -}; +#pragma once + +#include +#include +#include + +class Gui; + +class MessageBox { +public: + typedef enum { + NONE = 0, + OKAY = 1, + YES_NO = 2 + } MessageBoxOptions; + + MessageBox(std::string message, MessageBox::MessageBoxOptions options); + ~MessageBox(); + + MessageBox* setSelectionAction(std::function selectionAction); + MessageBox* setCustomDraw(std::function customDraw); + + void draw(Gui *gui); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + void onGesture(touchPosition startPosition, touchPosition endPosition, bool finish); + + void setProgress(s8 progress); + + void show(); + void hide(); + +private: + std::string m_message; + MessageBoxOptions m_options; + + u8 m_selectedOption; + s8 m_progress; + std::function m_selectionAction; + std::function m_customDraw; +}; diff --git a/include/ui_elements/scroll_selector.hpp b/include/ui_elements/scroll_selector.hpp index cc121f33..11606515 100644 --- a/include/ui_elements/scroll_selector.hpp +++ b/include/ui_elements/scroll_selector.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include - -#include "guis/gui.hpp" - -#include -#include - -class ScrollSelector { -public: - ScrollSelector(u16 x, u16 y, std::vector options); - ~ScrollSelector(); - - void draw(Gui *gui); - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - u16 m_x, m_y; - std::vector m_options; - u16 m_currSelection; - +#pragma once + +#include + +#include "guis/gui.hpp" + +#include +#include + +class ScrollSelector { +public: + ScrollSelector(u16 x, u16 y, std::vector options); + ~ScrollSelector(); + + void draw(Gui *gui); + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + u16 m_x, m_y; + std::vector m_options; + u16 m_currSelection; + }; \ No newline at end of file diff --git a/include/ui_elements/snackbar.hpp b/include/ui_elements/snackbar.hpp index f53e3a77..cf861796 100644 --- a/include/ui_elements/snackbar.hpp +++ b/include/ui_elements/snackbar.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include -#include - -class Gui; - -class Snackbar { -public: - Snackbar(std::string text); - ~Snackbar(); - - void show(); - - void update(); - void draw(Gui *gui); - - bool isDead(); - -private: - std::string m_text; - u16 m_displayTime; - bool m_isDead; -}; +#pragma once + +#include +#include + +class Gui; + +class Snackbar { +public: + Snackbar(std::string text); + ~Snackbar(); + + void show(); + + void update(); + void draw(Gui *gui); + + bool isDead(); + +private: + std::string m_text; + u16 m_displayTime; + bool m_isDead; +}; diff --git a/include/update_manager.hpp b/include/update_manager.hpp index df10faad..e4c7743c 100644 --- a/include/update_manager.hpp +++ b/include/update_manager.hpp @@ -1,20 +1,20 @@ -#pragma once - -#include -#include -#include - -typedef enum Updates { NONE, ERROR, EDITOR, EDIZON } Updates; - -class UpdateManager { -public: - UpdateManager(); - ~UpdateManager(); - - Updates checkUpdate(); - -private: - std::vector> m_downloadPaths; - std::string m_versionString; - -}; +#pragma once + +#include +#include +#include + +typedef enum Updates { NONE, ERROR, EDITOR, EDIZON } Updates; + +class UpdateManager { +public: + UpdateManager(); + ~UpdateManager(); + + Updates checkUpdate(); + +private: + std::vector> m_downloadPaths; + std::string m_versionString; + +}; diff --git a/include/upload_manager.hpp b/include/upload_manager.hpp index 23d426d1..922c013b 100644 --- a/include/upload_manager.hpp +++ b/include/upload_manager.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include -#include -#include - -#include - -#include "helpers/title.hpp" - -class UploadManager { -public: - UploadManager(); - ~UploadManager(); - - std::string upload(std::string path, std::string fileName, Title *title, std::string hash); - -private: - bool zip(std::vector paths, std::vector *zipData); - - CURL *m_curl; - std::string m_returnCode; - +#pragma once + +#include +#include +#include + +#include + +#include "helpers/title.hpp" + +class UploadManager { +public: + UploadManager(); + ~UploadManager(); + + std::string upload(std::string path, std::string fileName, Title *title, std::string hash); + +private: + bool zip(std::vector paths, std::vector *zipData); + + CURL *m_curl; + std::string m_returnCode; + }; \ No newline at end of file diff --git a/include/widgets/widget.hpp b/include/widgets/widget.hpp index daff35c4..d33b8fd5 100644 --- a/include/widgets/widget.hpp +++ b/include/widgets/widget.hpp @@ -1,70 +1,70 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include "guis/gui.hpp" -#include "scripting/interpreter.hpp" - -#define WIDGET_WIDTH 900 -#define WIDGET_HEIGHT 65 -#define WIDGET_SEPARATOR 10 -#define WIDGETS_PER_PAGE 6.0F -#define X_OFFSET 150 - -typedef enum WidgetDataType { - INT, - STRING -} WidgetDataType; - -class Widget; -typedef struct { std::string title; Widget *widget; } WidgetItem; -typedef std::map> WidgetItems; - -typedef enum { CATEGORIES, WIDGETS } WidgetRow; - -class Widget { -public: - Widget(Interpreter *interpreter, bool isDummy, std::string tooltip); - virtual ~Widget(); - - static inline u16 g_selectedWidgetIndex = 0; - static inline std::string g_selectedCategory; - static inline std::vector g_categories; - static inline WidgetRow g_selectedRow = CATEGORIES; - static inline u16 g_widgetPage; - static inline std::map g_widgetPageCnt; - static inline u8 g_categoryYOffset = 0; - - static void drawWidgets(Gui *gui, WidgetItems &widgets, u16 start, u16 end); - static void handleInput(u32 kdown, WidgetItems &widgets); - static void handleTouch(touchPosition &touch, WidgetItems &widgets); - - virtual void draw(Gui *gui, u16 x, u16 y) = 0; - virtual void onInput(u32 kdown) = 0; - virtual void onTouch(touchPosition &touch) = 0; - - s64 getIntegerValue(); - std::string getStringValue(); - bool isDummy(); - - void setIntegerValue(s64 value); - void setStringValue(std::string value); - - void setLuaArgs(std::vector intArgs, std::vector strArgs); - - static inline u16 g_stepSizeMultiplier = 1; - -protected: - Interpreter *m_interpreter; - WidgetDataType m_widgetDataType; - std::vector m_intArgs; - std::vector m_strArgs; - bool m_isDummy; - std::string m_tooltip; -}; +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "guis/gui.hpp" +#include "scripting/interpreter.hpp" + +#define WIDGET_WIDTH 900 +#define WIDGET_HEIGHT 65 +#define WIDGET_SEPARATOR 10 +#define WIDGETS_PER_PAGE 6.0F +#define X_OFFSET 150 + +typedef enum WidgetDataType { + INT, + STRING +} WidgetDataType; + +class Widget; +typedef struct { std::string title; Widget *widget; } WidgetItem; +typedef std::map> WidgetItems; + +typedef enum { CATEGORIES, WIDGETS } WidgetRow; + +class Widget { +public: + Widget(Interpreter *interpreter, bool isDummy, std::string tooltip); + virtual ~Widget(); + + static inline u16 g_selectedWidgetIndex = 0; + static inline std::string g_selectedCategory; + static inline std::vector g_categories; + static inline WidgetRow g_selectedRow = CATEGORIES; + static inline u16 g_widgetPage; + static inline std::map g_widgetPageCnt; + static inline u8 g_categoryYOffset = 0; + + static void drawWidgets(Gui *gui, WidgetItems &widgets, u16 start, u16 end); + static void handleInput(u32 kdown, WidgetItems &widgets); + static void handleTouch(touchPosition &touch, WidgetItems &widgets); + + virtual void draw(Gui *gui, u16 x, u16 y) = 0; + virtual void onInput(u32 kdown) = 0; + virtual void onTouch(touchPosition &touch) = 0; + + s64 getIntegerValue(); + std::string getStringValue(); + bool isDummy(); + + void setIntegerValue(s64 value); + void setStringValue(std::string value); + + void setLuaArgs(std::vector intArgs, std::vector strArgs); + + static inline u16 g_stepSizeMultiplier = 1; + +protected: + Interpreter *m_interpreter; + WidgetDataType m_widgetDataType; + std::vector m_intArgs; + std::vector m_strArgs; + bool m_isDummy; + std::string m_tooltip; +}; diff --git a/include/widgets/widget_button.hpp b/include/widgets/widget_button.hpp index a991c295..9e65a438 100644 --- a/include/widgets/widget_button.hpp +++ b/include/widgets/widget_button.hpp @@ -1,22 +1,22 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetButton : public Widget { -public: - WidgetButton(Interpreter *interpreter, std::string tooltip, std::string funcName); - - ~WidgetButton(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - std::string m_funcName; - std::string m_displayText; - -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetButton : public Widget { +public: + WidgetButton(Interpreter *interpreter, std::string tooltip, std::string funcName); + + ~WidgetButton(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + std::string m_funcName; + std::string m_displayText; + +}; diff --git a/include/widgets/widget_comment.hpp b/include/widgets/widget_comment.hpp index f237e24e..80c4e42b 100644 --- a/include/widgets/widget_comment.hpp +++ b/include/widgets/widget_comment.hpp @@ -1,21 +1,21 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetComment : public Widget { -public: - WidgetComment(Interpreter *interpreter, std::string tooltip, std::string text); - - ~WidgetComment(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - std::string m_strOnValue, m_text; - -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetComment : public Widget { +public: + WidgetComment(Interpreter *interpreter, std::string tooltip, std::string text); + + ~WidgetComment(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + std::string m_strOnValue, m_text; + +}; diff --git a/include/widgets/widget_list.hpp b/include/widgets/widget_list.hpp index 0a1145b5..65ab23a7 100644 --- a/include/widgets/widget_list.hpp +++ b/include/widgets/widget_list.hpp @@ -1,23 +1,23 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetList : public Widget { -public: - WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues); - WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues); - ~WidgetList(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - std::vector m_listItemNames; - std::vector m_intListItemValues; - std::vector m_strListItemValues; - -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetList : public Widget { +public: + WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues); + WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues); + ~WidgetList(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + std::vector m_listItemNames; + std::vector m_intListItemValues; + std::vector m_strListItemValues; + +}; diff --git a/include/widgets/widget_string.hpp b/include/widgets/widget_string.hpp index 9a9819c5..3ed6b12a 100644 --- a/include/widgets/widget_string.hpp +++ b/include/widgets/widget_string.hpp @@ -1,20 +1,20 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetString : public Widget { -public: - WidgetString(Interpreter *interpreter, bool isDummy, std::string tooltip, u8 minLength, u8 maxLength); - ~WidgetString(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - u8 m_minLength, m_maxLength; - -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetString : public Widget { +public: + WidgetString(Interpreter *interpreter, bool isDummy, std::string tooltip, u8 minLength, u8 maxLength); + ~WidgetString(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + u8 m_minLength, m_maxLength; + +}; diff --git a/include/widgets/widget_switch.hpp b/include/widgets/widget_switch.hpp index ab8ff84b..e5522fd3 100644 --- a/include/widgets/widget_switch.hpp +++ b/include/widgets/widget_switch.hpp @@ -1,23 +1,23 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetSwitch : public Widget { -public: - WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, s32 onValue, s32 offValue); - WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string onValue, std::string offValue); - - ~WidgetSwitch(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - s32 m_intOnValue, m_intOffValue; - std::string m_strOnValue, m_strOffValue; - -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetSwitch : public Widget { +public: + WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, s32 onValue, s32 offValue); + WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string onValue, std::string offValue); + + ~WidgetSwitch(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + s32 m_intOnValue, m_intOffValue; + std::string m_strOnValue, m_strOffValue; + +}; diff --git a/include/widgets/widget_value.hpp b/include/widgets/widget_value.hpp index 15b45056..c2898975 100644 --- a/include/widgets/widget_value.hpp +++ b/include/widgets/widget_value.hpp @@ -1,22 +1,22 @@ -#pragma once - -#include "widgets/widget.hpp" - -#include - -class WidgetValue : public Widget { -public: - WidgetValue(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string readEquation, std::string writeEquation, s64 minValue, s64 maxValue, u64 stepSize); - ~WidgetValue(); - - void draw(Gui *gui, u16 x, u16 y); - - void onInput(u32 kdown); - void onTouch(touchPosition &touch); - -private: - s64 m_currValue; - std::string m_readEquation, m_writeEquation; - s64 m_minValue, m_maxValue; - u64 m_stepSize; -}; +#pragma once + +#include "widgets/widget.hpp" + +#include + +class WidgetValue : public Widget { +public: + WidgetValue(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string readEquation, std::string writeEquation, s64 minValue, s64 maxValue, u64 stepSize); + ~WidgetValue(); + + void draw(Gui *gui, u16 x, u16 y); + + void onInput(u32 kdown); + void onTouch(touchPosition &touch); + +private: + s64 m_currValue; + std::string m_readEquation, m_writeEquation; + s64 m_minValue, m_maxValue; + u64 m_stepSize; +}; diff --git a/libs/lua/LICENSE.md b/libs/lua/LICENSE.md index bedcae42..381feb23 100644 --- a/libs/lua/LICENSE.md +++ b/libs/lua/LICENSE.md @@ -1,6 +1,6 @@ -Copyright © 1994–2018 Lua.org, PUC-Rio. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - +Copyright © 1994–2018 Lua.org, PUC-Rio. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/libs/lua/include/lapi.h b/libs/lua/include/lapi.h index 8e16ad53..54412605 100644 --- a/libs/lua/include/lapi.h +++ b/libs/lua/include/lapi.h @@ -1,24 +1,24 @@ -/* -** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $ -** Auxiliary functions from Lua API -** See Copyright Notice in lua.h -*/ - -#ifndef lapi_h -#define lapi_h - - -#include "llimits.h" -#include "lstate.h" - -#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ - "stack overflow");} - -#define adjustresults(L,nres) \ - { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } - -#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ - "not enough elements in the stack") - - -#endif +/* +** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "llimits.h" +#include "lstate.h" + +#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ + "stack overflow");} + +#define adjustresults(L,nres) \ + { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } + +#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ + "not enough elements in the stack") + + +#endif diff --git a/libs/lua/include/lauxlib.h b/libs/lua/include/lauxlib.h index 9857d3a8..c5fe688e 100644 --- a/libs/lua/include/lauxlib.h +++ b/libs/lua/include/lauxlib.h @@ -1,264 +1,264 @@ -/* -** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lauxlib_h -#define lauxlib_h - - -#include -#include - -#include "lua.h" - - - -/* extra error code for 'luaL_loadfilex' */ -#define LUA_ERRFILE (LUA_ERRERR+1) - - -/* key, in the registry, for table of loaded modules */ -#define LUA_LOADED_TABLE "_LOADED" - - -/* key, in the registry, for table of preloaded loaders */ -#define LUA_PRELOAD_TABLE "_PRELOAD" - - -typedef struct luaL_Reg { - const char *name; - lua_CFunction func; -} luaL_Reg; - - -#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) - -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); -#define luaL_checkversion(L) \ - luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) - -LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, - size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); - -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, - lua_Integer def); - -LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int arg); - -LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); -LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); -LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); -LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); - -LUALIB_API void (luaL_where) (lua_State *L, int lvl); -LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); - -LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, - const char *const lst[]); - -LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); -LUALIB_API int (luaL_execresult) (lua_State *L, int stat); - -/* predefined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) - -LUALIB_API int (luaL_ref) (lua_State *L, int t); -LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); - -LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); - -#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) - -LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); - -LUALIB_API lua_State *(luaL_newstate) (void); - -LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); - -LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, - const char *r); - -LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - -LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); - -LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, - const char *msg, int level); - -LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - - -#define luaL_newlibtable(L,l) \ - lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) - -#define luaL_newlib(L,l) \ - (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) - -#define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) -#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) -#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) - -#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) - -#define luaL_dofile(L, fn) \ - (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_dostring(L, s) \ - (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) - -#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) - -#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -typedef struct luaL_Buffer { - char *b; /* buffer address */ - size_t size; /* buffer size */ - size_t n; /* number of characters in buffer */ - lua_State *L; - char initb[LUAL_BUFFERSIZE]; /* initial buffer */ -} luaL_Buffer; - - -#define luaL_addchar(B,c) \ - ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ - ((B)->b[(B)->n++] = (c))) - -#define luaL_addsize(B,s) ((B)->n += (s)) - -LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); -LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); -LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); -LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); -LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); - -#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) - -/* }====================================================== */ - - - -/* -** {====================================================== -** File handles for IO library -** ======================================================= -*/ - -/* -** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and -** initial structure 'luaL_Stream' (it may contain other fields -** after that initial structure). -*/ - -#define LUA_FILEHANDLE "FILE*" - - -typedef struct luaL_Stream { - FILE *f; /* stream (NULL for incompletely created streams) */ - lua_CFunction closef; /* to close stream (NULL for closed streams) */ -} luaL_Stream; - -/* }====================================================== */ - - - -/* compatibility with old module system */ -#if defined(LUA_COMPAT_MODULE) - -LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, - int sizehint); -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); - -#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) - -#endif - - -/* -** {================================================================== -** "Abstraction Layer" for basic report of messages and errors -** =================================================================== -*/ - -/* print a string */ -#if !defined(lua_writestring) -#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#endif - -/* print a newline and flush the output */ -#if !defined(lua_writeline) -#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) -#endif - -/* print an error message */ -#if !defined(lua_writestringerror) -#define lua_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) -#endif - -/* }================================================================== */ - - -/* -** {============================================================ -** Compatibility with deprecated conversions -** ============================================================= -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) -#define luaL_optunsigned(L,a,d) \ - ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) - -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) - -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) - -#endif -/* }============================================================ */ - - - -#endif - - +/* +** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + + +/* extra error code for 'luaL_loadfilex' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +/* key, in the registry, for table of loaded modules */ +#define LUA_LOADED_TABLE "_LOADED" + + +/* key, in the registry, for table of preloaded loaders */ +#define LUA_PRELOAD_TABLE "_PRELOAD" + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) + +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); +LUALIB_API int (luaL_execresult) (lua_State *L, int stat); + +/* predefined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); + +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + + +#define luaL_newlibtable(L,l) \ + lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) + +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) + +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +typedef struct luaL_Buffer { + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ + lua_State *L; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ +} luaL_Buffer; + + +#define luaL_addchar(B,c) \ + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) + +#define luaL_addsize(B,s) ((B)->n += (s)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) + +/* }====================================================== */ + + + +/* +** {====================================================== +** File handles for IO library +** ======================================================= +*/ + +/* +** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and +** initial structure 'luaL_Stream' (it may contain other fields +** after that initial structure). +*/ + +#define LUA_FILEHANDLE "FILE*" + + +typedef struct luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} luaL_Stream; + +/* }====================================================== */ + + + +/* compatibility with old module system */ +#if defined(LUA_COMPAT_MODULE) + +LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, + int sizehint); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); + +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + +#endif + + +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + + +#endif + + diff --git a/libs/lua/include/lcode.h b/libs/lua/include/lcode.h index 882dc9c1..98d53e97 100644 --- a/libs/lua/include/lcode.h +++ b/libs/lua/include/lcode.h @@ -1,88 +1,88 @@ -/* -** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - -#ifndef lcode_h -#define lcode_h - -#include "llex.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" - - -/* -** Marks the end of a patch list. It is an invalid value both as an absolute -** address, and as a list link (would link an element to itself). -*/ -#define NO_JUMP (-1) - - -/* -** grep "ORDER OPR" if you change these enums (ORDER OP) -*/ -typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, - OPR_DIV, - OPR_IDIV, - OPR_BAND, OPR_BOR, OPR_BXOR, - OPR_SHL, OPR_SHR, - OPR_CONCAT, - OPR_EQ, OPR_LT, OPR_LE, - OPR_NE, OPR_GT, OPR_GE, - OPR_AND, OPR_OR, - OPR_NOBINOPR -} BinOpr; - - -typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; - - -/* get (pointer to) instruction of given 'expdesc' */ -#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) - -#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) - -#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) - -#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) - -LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); -LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); -LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); -LUAI_FUNC void luaK_fixline (FuncState *fs, int line); -LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); -LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); -LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); -LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); -LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); -LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); -LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); -LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); -LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); -LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_jump (FuncState *fs); -LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); -LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); -LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); -LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); -LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); -LUAI_FUNC int luaK_getlabel (FuncState *fs); -LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); -LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, - expdesc *v2, int line); -LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); - - -#endif +/* +** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums (ORDER OP) +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, + OPR_IDIV, + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, + OPR_CONCAT, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + + +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; + + +/* get (pointer to) instruction of given 'expdesc' */ +#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) + +#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) + +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); +LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); + + +#endif diff --git a/libs/lua/include/lctype.h b/libs/lua/include/lctype.h index b09b21a3..ee65cf5a 100644 --- a/libs/lua/include/lctype.h +++ b/libs/lua/include/lctype.h @@ -1,95 +1,95 @@ -/* -** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - -#ifndef lctype_h -#define lctype_h - -#include "lua.h" - - -/* -** WARNING: the functions defined here do not necessarily correspond -** to the similar functions in the standard C ctype.h. They are -** optimized for the specific needs of Lua -*/ - -#if !defined(LUA_USE_CTYPE) - -#if 'A' == 65 && '0' == 48 -/* ASCII case: can use its own tables; faster and fixed */ -#define LUA_USE_CTYPE 0 -#else -/* must use standard C ctype */ -#define LUA_USE_CTYPE 1 -#endif - -#endif - - -#if !LUA_USE_CTYPE /* { */ - -#include - -#include "llimits.h" - - -#define ALPHABIT 0 -#define DIGITBIT 1 -#define PRINTBIT 2 -#define SPACEBIT 3 -#define XDIGITBIT 4 - - -#define MASK(B) (1 << (B)) - - -/* -** add 1 to char to allow index -1 (EOZ) -*/ -#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) - -/* -** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' -*/ -#define lislalpha(c) testprop(c, MASK(ALPHABIT)) -#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) -#define lisdigit(c) testprop(c, MASK(DIGITBIT)) -#define lisspace(c) testprop(c, MASK(SPACEBIT)) -#define lisprint(c) testprop(c, MASK(PRINTBIT)) -#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) - -/* -** this 'ltolower' only works for alphabetic characters -*/ -#define ltolower(c) ((c) | ('A' ^ 'a')) - - -/* two more entries for 0 and -1 (EOZ) */ -LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; - - -#else /* }{ */ - -/* -** use standard C ctypes -*/ - -#include - - -#define lislalpha(c) (isalpha(c) || (c) == '_') -#define lislalnum(c) (isalnum(c) || (c) == '_') -#define lisdigit(c) (isdigit(c)) -#define lisspace(c) (isspace(c)) -#define lisprint(c) (isprint(c)) -#define lisxdigit(c) (isxdigit(c)) - -#define ltolower(c) (tolower(c)) - -#endif /* } */ - -#endif - +/* +** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + +#include "lua.h" + + +/* +** WARNING: the functions defined here do not necessarily correspond +** to the similar functions in the standard C ctype.h. They are +** optimized for the specific needs of Lua +*/ + +#if !defined(LUA_USE_CTYPE) + +#if 'A' == 65 && '0' == 48 +/* ASCII case: can use its own tables; faster and fixed */ +#define LUA_USE_CTYPE 0 +#else +/* must use standard C ctype */ +#define LUA_USE_CTYPE 1 +#endif + +#endif + + +#if !LUA_USE_CTYPE /* { */ + +#include + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + +/* +** this 'ltolower' only works for alphabetic characters +*/ +#define ltolower(c) ((c) | ('A' ^ 'a')) + + +/* two more entries for 0 and -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + + +#else /* }{ */ + +/* +** use standard C ctypes +*/ + +#include + + +#define lislalpha(c) (isalpha(c) || (c) == '_') +#define lislalnum(c) (isalnum(c) || (c) == '_') +#define lisdigit(c) (isdigit(c)) +#define lisspace(c) (isspace(c)) +#define lisprint(c) (isprint(c)) +#define lisxdigit(c) (isxdigit(c)) + +#define ltolower(c) (tolower(c)) + +#endif /* } */ + +#endif + diff --git a/libs/lua/include/ldebug.h b/libs/lua/include/ldebug.h index 8cea0ee0..08d51fd1 100644 --- a/libs/lua/include/ldebug.h +++ b/libs/lua/include/ldebug.h @@ -1,39 +1,39 @@ -/* -** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $ -** Auxiliary functions from Debug Interface module -** See Copyright Notice in lua.h -*/ - -#ifndef ldebug_h -#define ldebug_h - - -#include "lstate.h" - - -#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) - -#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) - -#define resethookcount(L) (L->hookcount = L->basehookcount) - - -LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, - const char *opname); -LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, - const char *msg); -LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); -LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, - TString *src, int line); -LUAI_FUNC l_noret luaG_errormsg (lua_State *L); -LUAI_FUNC void luaG_traceexec (lua_State *L); - - -#endif +/* +** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" + + +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + + +LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); +LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC void luaG_traceexec (lua_State *L); + + +#endif diff --git a/libs/lua/include/ldo.h b/libs/lua/include/ldo.h index 3b2983a3..6073a5c7 100644 --- a/libs/lua/include/ldo.h +++ b/libs/lua/include/ldo.h @@ -1,58 +1,58 @@ -/* -** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - -#ifndef ldo_h -#define ldo_h - - -#include "lobject.h" -#include "lstate.h" -#include "lzio.h" - - -/* -** Macro to check stack size and grow stack if needed. Parameters -** 'pre'/'pos' allow the macro to preserve a pointer into the -** stack across reallocations, doing the work only when needed. -** 'condmovestack' is used in heavy tests to force a stack reallocation -** at every check. -*/ -#define luaD_checkstackaux(L,n,pre,pos) \ - if (L->stack_last - L->top <= (n)) \ - { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } - -/* In general, 'pre'/'pos' are empty (nothing to save) */ -#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) - - - -#define savestack(L,p) ((char *)(p) - (char *)L->stack) -#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) - - -/* type of protected functions, to be ran by 'runprotected' */ -typedef void (*Pfunc) (lua_State *L, void *ud); - -LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, - const char *mode); -LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); -LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); -LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); -LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, - int nres); -LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); -LUAI_FUNC void luaD_growstack (lua_State *L, int n); -LUAI_FUNC void luaD_shrinkstack (lua_State *L); -LUAI_FUNC void luaD_inctop (lua_State *L); - -LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); -LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); - -#endif - +/* +** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +/* +** Macro to check stack size and grow stack if needed. Parameters +** 'pre'/'pos' allow the macro to preserve a pointer into the +** stack across reallocations, doing the work only when needed. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (L->stack_last - L->top <= (n)) \ + { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } + +/* In general, 'pre'/'pos' are empty (nothing to save) */ +#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) + + + +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) + + +/* type of protected functions, to be ran by 'runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, + int nres); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); + +LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +#endif + diff --git a/libs/lua/include/lfunc.h b/libs/lua/include/lfunc.h index c916e987..30c55ea6 100644 --- a/libs/lua/include/lfunc.h +++ b/libs/lua/include/lfunc.h @@ -1,61 +1,61 @@ -/* -** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - -#ifndef lfunc_h -#define lfunc_h - - -#include "lobject.h" - - -#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ - cast(int, sizeof(TValue)*((n)-1))) - -#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ - cast(int, sizeof(TValue *)*((n)-1))) - - -/* test whether thread is in 'twups' list */ -#define isintwups(L) (L->twups != L) - - -/* -** maximum number of upvalues in a closure (both C and Lua). (Value -** must fit in a VM register.) -*/ -#define MAXUPVAL 255 - - -/* -** Upvalues for Lua closures -*/ -struct UpVal { - TValue *v; /* points to stack or to its own value */ - lu_mem refcount; /* reference counter */ - union { - struct { /* (when open) */ - UpVal *next; /* linked list */ - int touched; /* mark to avoid cycles with dead threads */ - } open; - TValue value; /* the value (when closed) */ - } u; -}; - -#define upisopen(up) ((up)->v != &(up)->u.value) - - -LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); -LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); -LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); -LUAI_FUNC void luaF_close (lua_State *L, StkId level); -LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, - int pc); - - -#endif +/* +** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + +/* test whether thread is in 'twups' list */ +#define isintwups(L) (L->twups != L) + + +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in a VM register.) +*/ +#define MAXUPVAL 255 + + +/* +** Upvalues for Lua closures +*/ +struct UpVal { + TValue *v; /* points to stack or to its own value */ + lu_mem refcount; /* reference counter */ + union { + struct { /* (when open) */ + UpVal *next; /* linked list */ + int touched; /* mark to avoid cycles with dead threads */ + } open; + TValue value; /* the value (when closed) */ + } u; +}; + +#define upisopen(up) ((up)->v != &(up)->u.value) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/libs/lua/include/lgc.h b/libs/lua/include/lgc.h index 425cd7ce..aa7976e1 100644 --- a/libs/lua/include/lgc.h +++ b/libs/lua/include/lgc.h @@ -1,147 +1,147 @@ -/* -** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - -#ifndef lgc_h -#define lgc_h - - -#include "lobject.h" -#include "lstate.h" - -/* -** Collectable objects may have one of three colors: white, which -** means the object is not marked; gray, which means the -** object is marked, but its references may be not marked; and -** black, which means that the object and all its references are marked. -** The main invariant of the garbage collector, while marking objects, -** is that a black object can never point to a white one. Moreover, -** any gray object must be in a "gray list" (gray, grayagain, weak, -** allweak, ephemeron) so that it can be visited again before finishing -** the collection cycle. These lists have no meaning when the invariant -** is not being enforced (e.g., sweep phase). -*/ - - - -/* how much to allocate before next GC step */ -#if !defined(GCSTEPSIZE) -/* ~100 small strings */ -#define GCSTEPSIZE (cast_int(100 * sizeof(TString))) -#endif - - -/* -** Possible states of the Garbage Collector -*/ -#define GCSpropagate 0 -#define GCSatomic 1 -#define GCSswpallgc 2 -#define GCSswpfinobj 3 -#define GCSswptobefnz 4 -#define GCSswpend 5 -#define GCScallfin 6 -#define GCSpause 7 - - -#define issweepphase(g) \ - (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) - - -/* -** macro to tell when main invariant (white objects cannot point to black -** ones) must be kept. During a collection, the sweep -** phase may break the invariant, as objects turned white may point to -** still-black objects. The invariant is restored when sweep ends and -** all objects are white again. -*/ - -#define keepinvariant(g) ((g)->gcstate <= GCSatomic) - - -/* -** some useful bit tricks -*/ -#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) -#define setbits(x,m) ((x) |= (m)) -#define testbits(x,m) ((x) & (m)) -#define bitmask(b) (1<<(b)) -#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) -#define l_setbit(x,b) setbits(x, bitmask(b)) -#define resetbit(x,b) resetbits(x, bitmask(b)) -#define testbit(x,b) testbits(x, bitmask(b)) - - -/* Layout for bit use in 'marked' field: */ -#define WHITE0BIT 0 /* object is white (type 0) */ -#define WHITE1BIT 1 /* object is white (type 1) */ -#define BLACKBIT 2 /* object is black */ -#define FINALIZEDBIT 3 /* object has been marked for finalization */ -/* bit 7 is currently used by tests (luaL_checkmemory) */ - -#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) - - -#define iswhite(x) testbits((x)->marked, WHITEBITS) -#define isblack(x) testbit((x)->marked, BLACKBIT) -#define isgray(x) /* neither white nor black */ \ - (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) - -#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) - -#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) -#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) -#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) - -#define changewhite(x) ((x)->marked ^= WHITEBITS) -#define gray2black(x) l_setbit((x)->marked, BLACKBIT) - -#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) - - -/* -** Does one step of collection when debt becomes positive. 'pre'/'pos' -** allows some adjustments to be done only when needed. macro -** 'condchangemem' is used only for heavy tests (forcing a full -** GC cycle on every opportunity) -*/ -#define luaC_condGC(L,pre,pos) \ - { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ - condchangemem(L,pre,pos); } - -/* more often than not, 'pre'/'pos' are empty */ -#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) - - -#define luaC_barrier(L,p,v) ( \ - (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ - luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) - -#define luaC_barrierback(L,p,v) ( \ - (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ - luaC_barrierback_(L,p) : cast_void(0)) - -#define luaC_objbarrier(L,p,o) ( \ - (isblack(p) && iswhite(o)) ? \ - luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) - -#define luaC_upvalbarrier(L,uv) ( \ - (iscollectable((uv)->v) && !upisopen(uv)) ? \ - luaC_upvalbarrier_(L,uv) : cast_void(0)) - -LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); -LUAI_FUNC void luaC_freeallobjects (lua_State *L); -LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); -LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); -LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); -LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); -LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); -LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); -LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); - - -#endif +/* +** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which +** means the object is not marked; gray, which means the +** object is marked, but its references may be not marked; and +** black, which means that the object and all its references are marked. +** The main invariant of the garbage collector, while marking objects, +** is that a black object can never point to a white one. Moreover, +** any gray object must be in a "gray list" (gray, grayagain, weak, +** allweak, ephemeron) so that it can be visited again before finishing +** the collection cycle. These lists have no meaning when the invariant +** is not being enforced (e.g., sweep phase). +*/ + + + +/* how much to allocate before next GC step */ +#if !defined(GCSTEPSIZE) +/* ~100 small strings */ +#define GCSTEPSIZE (cast_int(100 * sizeof(TString))) +#endif + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSatomic 1 +#define GCSswpallgc 2 +#define GCSswpfinobj 3 +#define GCSswptobefnz 4 +#define GCSswpend 5 +#define GCScallfin 6 +#define GCSpause 7 + + +#define issweepphase(g) \ + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) + + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep +** phase may break the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. +*/ + +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) + + +/* +** some useful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) + + +/* Layout for bit use in 'marked' field: */ +#define WHITE0BIT 0 /* object is white (type 0) */ +#define WHITE1BIT 1 /* object is white (type 1) */ +#define BLACKBIT 2 /* object is black */ +#define FINALIZEDBIT 3 /* object has been marked for finalization */ +/* bit 7 is currently used by tests (luaL_checkmemory) */ + +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) + +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) + +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) +#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) + +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->marked, BLACKBIT) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } + +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) + + +#define luaC_barrier(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) + +#define luaC_barrierback(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrierback_(L,p) : cast_void(0)) + +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) + +#define luaC_upvalbarrier(L,uv) ( \ + (iscollectable((uv)->v) && !upisopen(uv)) ? \ + luaC_upvalbarrier_(L,uv) : cast_void(0)) + +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); +LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); +LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); +LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); + + +#endif diff --git a/libs/lua/include/llex.h b/libs/lua/include/llex.h index 2ed0af66..1c893ee8 100644 --- a/libs/lua/include/llex.h +++ b/libs/lua/include/llex.h @@ -1,85 +1,85 @@ -/* -** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - -#ifndef llex_h -#define llex_h - -#include "lobject.h" -#include "lzio.h" - - -#define FIRST_RESERVED 257 - - -#if !defined(LUA_ENV) -#define LUA_ENV "_ENV" -#endif - - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER RESERVED" -*/ -enum RESERVED { - /* terminal symbols denoted by reserved words */ - TK_AND = FIRST_RESERVED, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, - TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, - TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, - /* other terminal symbols */ - TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, - TK_SHL, TK_SHR, - TK_DBCOLON, TK_EOS, - TK_FLT, TK_INT, TK_NAME, TK_STRING -}; - -/* number of reserved words */ -#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) - - -typedef union { - lua_Number r; - lua_Integer i; - TString *ts; -} SemInfo; /* semantics information */ - - -typedef struct Token { - int token; - SemInfo seminfo; -} Token; - - -/* state of the lexer plus state of the parser when shared by all - functions */ -typedef struct LexState { - int current; /* current character (charint) */ - int linenumber; /* input line counter */ - int lastline; /* line of last token 'consumed' */ - Token t; /* current token */ - Token lookahead; /* look ahead token */ - struct FuncState *fs; /* current function (parser) */ - struct lua_State *L; - ZIO *z; /* input stream */ - Mbuffer *buff; /* buffer for tokens */ - Table *h; /* to avoid collection/reuse strings */ - struct Dyndata *dyd; /* dynamic structures used by the parser */ - TString *source; /* current source name */ - TString *envn; /* environment variable name */ -} LexState; - - -LUAI_FUNC void luaX_init (lua_State *L); -LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, - TString *source, int firstchar); -LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); -LUAI_FUNC void luaX_next (LexState *ls); -LUAI_FUNC int luaX_lookahead (LexState *ls); -LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); -LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); - - -#endif +/* +** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 257 + + +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ +enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING +}; + +/* number of reserved words */ +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) + + +typedef union { + lua_Number r; + lua_Integer i; + TString *ts; +} SemInfo; /* semantics information */ + + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; + + +/* state of the lexer plus state of the parser when shared by all + functions */ +typedef struct LexState { + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token 'consumed' */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* current function (parser) */ + struct lua_State *L; + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ + TString *source; /* current source name */ + TString *envn; /* environment variable name */ +} LexState; + + +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, + TString *source, int firstchar); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC int luaX_lookahead (LexState *ls); +LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); + + +#endif diff --git a/libs/lua/include/llimits.h b/libs/lua/include/llimits.h index d1036f6b..abdc4024 100644 --- a/libs/lua/include/llimits.h +++ b/libs/lua/include/llimits.h @@ -1,323 +1,323 @@ -/* -** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $ -** Limits, basic types, and some other 'installation-dependent' definitions -** See Copyright Notice in lua.h -*/ - -#ifndef llimits_h -#define llimits_h - - -#include -#include - - -#include "lua.h" - -/* -** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count -** the total memory used by Lua (in bytes). Usually, 'size_t' and -** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. -*/ -#if defined(LUAI_MEM) /* { external definitions? */ -typedef LUAI_UMEM lu_mem; -typedef LUAI_MEM l_mem; -#elif LUAI_BITSINT >= 32 /* }{ */ -typedef size_t lu_mem; -typedef ptrdiff_t l_mem; -#else /* 16-bit ints */ /* }{ */ -typedef unsigned long lu_mem; -typedef long l_mem; -#endif /* } */ - - -/* chars used as small naturals (so that 'char' is reserved for characters) */ -typedef unsigned char lu_byte; - - -/* maximum value for size_t */ -#define MAX_SIZET ((size_t)(~(size_t)0)) - -/* maximum size visible for Lua (must be representable in a lua_Integer */ -#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ - : (size_t)(LUA_MAXINTEGER)) - - -#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) - -#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) - - -#define MAX_INT INT_MAX /* maximum value of an int */ - - -/* -** conversion of pointer to unsigned integer: -** this is for hashing only; there is no problem if the integer -** cannot hold the whole pointer value -*/ -#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) - - - -/* type to ensure maximum alignment */ -#if defined(LUAI_USER_ALIGNMENT_T) -typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; -#else -typedef union { - lua_Number n; - double u; - void *s; - lua_Integer i; - long l; -} L_Umaxalign; -#endif - - - -/* types of 'usual argument conversions' for lua_Number and lua_Integer */ -typedef LUAI_UACNUMBER l_uacNumber; -typedef LUAI_UACINT l_uacInt; - - -/* internal assertions for in-house debugging */ -#if defined(lua_assert) -#define check_exp(c,e) (lua_assert(c), (e)) -/* to avoid problems with conditions too long */ -#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) -#else -#define lua_assert(c) ((void)0) -#define check_exp(c,e) (e) -#define lua_longassert(c) ((void)0) -#endif - -/* -** assertion for checking API calls -*/ -#if !defined(luai_apicheck) -#define luai_apicheck(l,e) lua_assert(e) -#endif - -#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) - - -/* macro to avoid warnings about unused variables */ -#if !defined(UNUSED) -#define UNUSED(x) ((void)(x)) -#endif - - -/* type casts (a macro highlights casts in the code) */ -#define cast(t, exp) ((t)(exp)) - -#define cast_void(i) cast(void, (i)) -#define cast_byte(i) cast(lu_byte, (i)) -#define cast_num(i) cast(lua_Number, (i)) -#define cast_int(i) cast(int, (i)) -#define cast_uchar(i) cast(unsigned char, (i)) - - -/* cast a signed lua_Integer to lua_Unsigned */ -#if !defined(l_castS2U) -#define l_castS2U(i) ((lua_Unsigned)(i)) -#endif - -/* -** cast a lua_Unsigned to a signed lua_Integer; this cast is -** not strict ISO C, but two-complement architectures should -** work fine. -*/ -#if !defined(l_castU2S) -#define l_castU2S(i) ((lua_Integer)(i)) -#endif - - -/* -** non-return type -*/ -#if defined(__GNUC__) -#define l_noret void __attribute__((noreturn)) -#elif defined(_MSC_VER) && _MSC_VER >= 1200 -#define l_noret void __declspec(noreturn) -#else -#define l_noret void -#endif - - - -/* -** maximum depth for nested C calls and syntactical nested non-terminals -** in a program. (Value must fit in an unsigned short int.) -*/ -#if !defined(LUAI_MAXCCALLS) -#define LUAI_MAXCCALLS 200 -#endif - - - -/* -** type for virtual-machine instructions; -** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) -*/ -#if LUAI_BITSINT >= 32 -typedef unsigned int Instruction; -#else -typedef unsigned long Instruction; -#endif - - - -/* -** Maximum length for short strings, that is, strings that are -** internalized. (Cannot be smaller than reserved words or tags for -** metamethods, as these strings must be internalized; -** #("function") = 8, #("__newindex") = 10.) -*/ -#if !defined(LUAI_MAXSHORTLEN) -#define LUAI_MAXSHORTLEN 40 -#endif - - -/* -** Initial size for the string table (must be power of 2). -** The Lua core alone registers ~50 strings (reserved words + -** metaevent keys + a few others). Libraries would typically add -** a few dozens more. -*/ -#if !defined(MINSTRTABSIZE) -#define MINSTRTABSIZE 128 -#endif - - -/* -** Size of cache for strings in the API. 'N' is the number of -** sets (better be a prime) and "M" is the size of each set (M == 1 -** makes a direct cache.) -*/ -#if !defined(STRCACHE_N) -#define STRCACHE_N 53 -#define STRCACHE_M 2 -#endif - - -/* minimum size for string buffer */ -#if !defined(LUA_MINBUFFER) -#define LUA_MINBUFFER 32 -#endif - - -/* -** macros that are executed whenever program enters the Lua core -** ('lua_lock') and leaves the core ('lua_unlock') -*/ -#if !defined(lua_lock) -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) -#endif - -/* -** macro executed during Lua functions at points where the -** function can yield. -*/ -#if !defined(luai_threadyield) -#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} -#endif - - -/* -** these macros allow user-specific actions on threads when you defined -** LUAI_EXTRASPACE and need to do something extra when a thread is -** created/deleted/resumed/yielded. -*/ -#if !defined(luai_userstateopen) -#define luai_userstateopen(L) ((void)L) -#endif - -#if !defined(luai_userstateclose) -#define luai_userstateclose(L) ((void)L) -#endif - -#if !defined(luai_userstatethread) -#define luai_userstatethread(L,L1) ((void)L) -#endif - -#if !defined(luai_userstatefree) -#define luai_userstatefree(L,L1) ((void)L) -#endif - -#if !defined(luai_userstateresume) -#define luai_userstateresume(L,n) ((void)L) -#endif - -#if !defined(luai_userstateyield) -#define luai_userstateyield(L,n) ((void)L) -#endif - - - -/* -** The luai_num* macros define the primitive operations over numbers. -*/ - -/* floor division (defined as 'floor(a/b)') */ -#if !defined(luai_numidiv) -#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) -#endif - -/* float division */ -#if !defined(luai_numdiv) -#define luai_numdiv(L,a,b) ((a)/(b)) -#endif - -/* -** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when -** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of -** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) -** ~= floor(a/b)'. That happens when the division has a non-integer -** negative result, which is equivalent to the test below. -*/ -#if !defined(luai_nummod) -#define luai_nummod(L,a,b,m) \ - { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } -#endif - -/* exponentiation */ -#if !defined(luai_numpow) -#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) -#endif - -/* the others are quite standard operations */ -#if !defined(luai_numadd) -#define luai_numadd(L,a,b) ((a)+(b)) -#define luai_numsub(L,a,b) ((a)-(b)) -#define luai_nummul(L,a,b) ((a)*(b)) -#define luai_numunm(L,a) (-(a)) -#define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(a,b) ((a)<(b)) -#define luai_numle(a,b) ((a)<=(b)) -#define luai_numisnan(a) (!luai_numeq((a), (a))) -#endif - - - - - -/* -** macro to control inclusion of some hard tests on stack reallocation -*/ -#if !defined(HARDSTACKTESTS) -#define condmovestack(L,pre,pos) ((void)0) -#else -/* realloc stack keeping its size */ -#define condmovestack(L,pre,pos) \ - { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } -#endif - -#if !defined(HARDMEMTESTS) -#define condchangemem(L,pre,pos) ((void)0) -#else -#define condchangemem(L,pre,pos) \ - { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } -#endif - -#endif +/* +** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $ +** Limits, basic types, and some other 'installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + +#include "lua.h" + +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ +typedef LUAI_UMEM lu_mem; +typedef LUAI_MEM l_mem; +#elif LUAI_BITSINT >= 32 /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ + + +/* chars used as small naturals (so that 'char' is reserved for characters) */ +typedef unsigned char lu_byte; + + +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) + +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) + + +#define MAX_INT INT_MAX /* maximum value of an int */ + + +/* +** conversion of pointer to unsigned integer: +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value +*/ +#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) + + + +/* type to ensure maximum alignment */ +#if defined(LUAI_USER_ALIGNMENT_T) +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; +#else +typedef union { + lua_Number n; + double u; + void *s; + lua_Integer i; + long l; +} L_Umaxalign; +#endif + + + +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ +typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; + + +/* internal assertions for in-house debugging */ +#if defined(lua_assert) +#define check_exp(c,e) (lua_assert(c), (e)) +/* to avoid problems with conditions too long */ +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) +#else +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define lua_longassert(c) ((void)0) +#endif + +/* +** assertion for checking API calls +*/ +#if !defined(luai_apicheck) +#define luai_apicheck(l,e) lua_assert(e) +#endif + +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + + +/* macro to avoid warnings about unused variables */ +#if !defined(UNUSED) +#define UNUSED(x) ((void)(x)) +#endif + + +/* type casts (a macro highlights casts in the code) */ +#define cast(t, exp) ((t)(exp)) + +#define cast_void(i) cast(void, (i)) +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) +#define cast_uchar(i) cast(unsigned char, (i)) + + +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + +/* +** non-return type +*/ +#if defined(__GNUC__) +#define l_noret void __attribute__((noreturn)) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 +#define l_noret void __declspec(noreturn) +#else +#define l_noret void +#endif + + + +/* +** maximum depth for nested C calls and syntactical nested non-terminals +** in a program. (Value must fit in an unsigned short int.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + + +/* +** type for virtual-machine instructions; +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +#if LUAI_BITSINT >= 32 +typedef unsigned int Instruction; +#else +typedef unsigned long Instruction; +#endif + + + +/* +** Maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags for +** metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#if !defined(LUAI_MAXSHORTLEN) +#define LUAI_MAXSHORTLEN 40 +#endif + + +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ +#if !defined(MINSTRTABSIZE) +#define MINSTRTABSIZE 128 +#endif + + +/* +** Size of cache for strings in the API. 'N' is the number of +** sets (better be a prime) and "M" is the size of each set (M == 1 +** makes a direct cache.) +*/ +#if !defined(STRCACHE_N) +#define STRCACHE_N 53 +#define STRCACHE_M 2 +#endif + + +/* minimum size for string buffer */ +#if !defined(LUA_MINBUFFER) +#define LUA_MINBUFFER 32 +#endif + + +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ +#if !defined(luai_threadyield) +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** these macros allow user-specific actions on threads when you defined +** LUAI_EXTRASPACE and need to do something extra when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L,L1) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + +/* +** The luai_num* macros define the primitive operations over numbers. +*/ + +/* floor division (defined as 'floor(a/b)') */ +#if !defined(luai_numidiv) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) +#endif + +/* float division */ +#if !defined(luai_numdiv) +#define luai_numdiv(L,a,b) ((a)/(b)) +#endif + +/* +** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when +** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of +** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) +** ~= floor(a/b)'. That happens when the division has a non-integer +** negative result, which is equivalent to the test below. +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } +#endif + +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) +#endif + +/* the others are quite standard operations */ +#if !defined(luai_numadd) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) +#endif + + + + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L,pre,pos) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L,pre,pos) \ + { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L,pre,pos) ((void)0) +#else +#define condchangemem(L,pre,pos) \ + { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } +#endif + +#endif diff --git a/libs/lua/include/lmem.h b/libs/lua/include/lmem.h index 357b1e43..234a5c5b 100644 --- a/libs/lua/include/lmem.h +++ b/libs/lua/include/lmem.h @@ -1,69 +1,69 @@ -/* -** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - -#ifndef lmem_h -#define lmem_h - - -#include - -#include "llimits.h" -#include "lua.h" - - -/* -** This macro reallocs a vector 'b' from 'on' to 'n' elements, where -** each element has size 'e'. In case of arithmetic overflow of the -** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because -** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). -** -** (The macro is somewhat complex to avoid warnings: The 'sizeof' -** comparison avoids a runtime comparison when overflow cannot occur. -** The compiler should be able to optimize the real test by itself, but -** when it does it, it may give a warning about "comparison is always -** false due to limited range of data type"; the +1 tricks the compiler, -** avoiding this warning but also this optimization.) -*/ -#define luaM_reallocv(L,b,on,n,e) \ - (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ - ? luaM_toobig(L) : cast_void(0)) , \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e))) - -/* -** Arrays of chars do not need any test -*/ -#define luaM_reallocvchar(L,b,on,n) \ - cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) - -#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) -#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) - -#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) -#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) -#define luaM_newvector(L,n,t) \ - cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) - -#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) - -#define luaM_growvector(L,v,nelems,size,t,limit,e) \ - if ((nelems)+1 > (size)) \ - ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) - -#define luaM_reallocvector(L, v,oldn,n,t) \ - ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) - -LUAI_FUNC l_noret luaM_toobig (lua_State *L); - -/* not to be called directly */ -LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, - size_t size); -LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, - size_t size_elem, int limit, - const char *what); - -#endif - +/* +** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#include + +#include "llimits.h" +#include "lua.h" + + +/* +** This macro reallocs a vector 'b' from 'on' to 'n' elements, where +** each element has size 'e'. In case of arithmetic overflow of the +** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because +** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). +** +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) +*/ +#define luaM_reallocv(L,b,on,n,e) \ + (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ + ? luaM_toobig(L) : cast_void(0)) , \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e))) + +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + +#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) +#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) + +#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) +#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L,n,t) \ + cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) + +#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + if ((nelems)+1 > (size)) \ + ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + +LUAI_FUNC l_noret luaM_toobig (lua_State *L); + +/* not to be called directly */ +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *what); + +#endif + diff --git a/libs/lua/include/lobject.h b/libs/lua/include/lobject.h index 24088614..40b1f19a 100644 --- a/libs/lua/include/lobject.h +++ b/libs/lua/include/lobject.h @@ -1,549 +1,549 @@ -/* -** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $ -** Type definitions for Lua objects -** See Copyright Notice in lua.h -*/ - - -#ifndef lobject_h -#define lobject_h - - -#include - - -#include "llimits.h" -#include "lua.h" - - -/* -** Extra tags for non-values -*/ -#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ -#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ - -/* -** number of all possible tags (including LUA_TNONE but excluding DEADKEY) -*/ -#define LUA_TOTALTAGS (LUA_TPROTO + 2) - - -/* -** tags for Tagged Values have the following use of bits: -** bits 0-3: actual tag (a LUA_T* value) -** bits 4-5: variant bits -** bit 6: whether value is collectable -*/ - - -/* -** LUA_TFUNCTION variants: -** 0 - Lua function -** 1 - light C function -** 2 - regular C function (closure) -*/ - -/* Variant tags for functions */ -#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ -#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ -#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ - - -/* Variant tags for strings */ -#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ -#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ - - -/* Variant tags for numbers */ -#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ -#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ - - -/* Bit mark for collectable types */ -#define BIT_ISCOLLECTABLE (1 << 6) - -/* mark a tag as collectable */ -#define ctb(t) ((t) | BIT_ISCOLLECTABLE) - - -/* -** Common type for all collectable objects -*/ -typedef struct GCObject GCObject; - - -/* -** Common Header for all collectable objects (in macro form, to be -** included in other objects) -*/ -#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked - - -/* -** Common type has only the common header -*/ -struct GCObject { - CommonHeader; -}; - - - - -/* -** Tagged Values. This is the basic representation of values in Lua, -** an actual value plus a tag with its type. -*/ - -/* -** Union of all Lua values -*/ -typedef union Value { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ - lua_Integer i; /* integer numbers */ - lua_Number n; /* float numbers */ -} Value; - - -#define TValuefields Value value_; int tt_ - - -typedef struct lua_TValue { - TValuefields; -} TValue; - - - -/* macro defining a nil value */ -#define NILCONSTANT {NULL}, LUA_TNIL - - -#define val_(o) ((o)->value_) - - -/* raw type tag of a TValue */ -#define rttype(o) ((o)->tt_) - -/* tag with no variants (bits 0-3) */ -#define novariant(x) ((x) & 0x0F) - -/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ -#define ttype(o) (rttype(o) & 0x3F) - -/* type tag of a TValue with no variants (bits 0-3) */ -#define ttnov(o) (novariant(rttype(o))) - - -/* Macros to test type */ -#define checktag(o,t) (rttype(o) == (t)) -#define checktype(o,t) (ttnov(o) == (t)) -#define ttisnumber(o) checktype((o), LUA_TNUMBER) -#define ttisfloat(o) checktag((o), LUA_TNUMFLT) -#define ttisinteger(o) checktag((o), LUA_TNUMINT) -#define ttisnil(o) checktag((o), LUA_TNIL) -#define ttisboolean(o) checktag((o), LUA_TBOOLEAN) -#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) -#define ttisstring(o) checktype((o), LUA_TSTRING) -#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) -#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) -#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) -#define ttisfunction(o) checktype(o, LUA_TFUNCTION) -#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) -#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) -#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) -#define ttislcf(o) checktag((o), LUA_TLCF) -#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) -#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) -#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) - - -/* Macros to access values */ -#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) -#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) -#define nvalue(o) check_exp(ttisnumber(o), \ - (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) -#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) -#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) -#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) -#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) -#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) -#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) -#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) -#define fvalue(o) check_exp(ttislcf(o), val_(o).f) -#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) -#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) -#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) -/* a dead value may get the 'gc' field, but cannot access its contents */ -#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) - -#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) - - -#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) - - -/* Macros for internal tests */ -#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) - -#define checkliveness(L,obj) \ - lua_longassert(!iscollectable(obj) || \ - (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) - - -/* Macros to set values */ -#define settt_(o,t) ((o)->tt_=(t)) - -#define setfltvalue(obj,x) \ - { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } - -#define chgfltvalue(obj,x) \ - { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } - -#define setivalue(obj,x) \ - { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } - -#define chgivalue(obj,x) \ - { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } - -#define setnilvalue(obj) settt_(obj, LUA_TNIL) - -#define setfvalue(obj,x) \ - { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } - -#define setpvalue(obj,x) \ - { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } - -#define setbvalue(obj,x) \ - { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } - -#define setgcovalue(L,obj,x) \ - { TValue *io = (obj); GCObject *i_g=(x); \ - val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } - -#define setsvalue(L,obj,x) \ - { TValue *io = (obj); TString *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ - checkliveness(L,io); } - -#define setuvalue(L,obj,x) \ - { TValue *io = (obj); Udata *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ - checkliveness(L,io); } - -#define setthvalue(L,obj,x) \ - { TValue *io = (obj); lua_State *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ - checkliveness(L,io); } - -#define setclLvalue(L,obj,x) \ - { TValue *io = (obj); LClosure *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ - checkliveness(L,io); } - -#define setclCvalue(L,obj,x) \ - { TValue *io = (obj); CClosure *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ - checkliveness(L,io); } - -#define sethvalue(L,obj,x) \ - { TValue *io = (obj); Table *x_ = (x); \ - val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ - checkliveness(L,io); } - -#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) - - - -#define setobj(L,obj1,obj2) \ - { TValue *io1=(obj1); *io1 = *(obj2); \ - (void)L; checkliveness(L,io1); } - - -/* -** different types of assignments, according to destination -*/ - -/* from stack to (same) stack */ -#define setobjs2s setobj -/* to stack (not from same stack) */ -#define setobj2s setobj -#define setsvalue2s setsvalue -#define sethvalue2s sethvalue -#define setptvalue2s setptvalue -/* from table to same table */ -#define setobjt2t setobj -/* to new object */ -#define setobj2n setobj -#define setsvalue2n setsvalue - -/* to table (define it as an expression to be used in macros) */ -#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) - - - - -/* -** {====================================================== -** types and prototypes -** ======================================================= -*/ - - -typedef TValue *StkId; /* index to stack elements */ - - - - -/* -** Header for string value; string bytes follow the end of this structure -** (aligned according to 'UTString'; see next). -*/ -typedef struct TString { - CommonHeader; - lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - lu_byte shrlen; /* length for short strings */ - unsigned int hash; - union { - size_t lnglen; /* length for long strings */ - struct TString *hnext; /* linked list for hash table */ - } u; -} TString; - - -/* -** Ensures that address after this type is always fully aligned. -*/ -typedef union UTString { - L_Umaxalign dummy; /* ensures maximum alignment for strings */ - TString tsv; -} UTString; - - -/* -** Get the actual string (array of bytes) from a 'TString'. -** (Access to 'extra' ensures that value is really a 'TString'.) -*/ -#define getstr(ts) \ - check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) - - -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(tsvalue(o)) - -/* get string length from 'TString *s' */ -#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) - -/* get string length from 'TValue *o' */ -#define vslen(o) tsslen(tsvalue(o)) - - -/* -** Header for userdata; memory area follows the end of this structure -** (aligned according to 'UUdata'; see next). -*/ -typedef struct Udata { - CommonHeader; - lu_byte ttuv_; /* user value's tag */ - struct Table *metatable; - size_t len; /* number of bytes */ - union Value user_; /* user value */ -} Udata; - - -/* -** Ensures that address after this type is always fully aligned. -*/ -typedef union UUdata { - L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ - Udata uv; -} UUdata; - - -/* -** Get the address of memory block inside 'Udata'. -** (Access to 'ttuv_' ensures that value is really a 'Udata'.) -*/ -#define getudatamem(u) \ - check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) - -#define setuservalue(L,u,o) \ - { const TValue *io=(o); Udata *iu = (u); \ - iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ - checkliveness(L,io); } - - -#define getuservalue(L,u,o) \ - { TValue *io=(o); const Udata *iu = (u); \ - io->value_ = iu->user_; settt_(io, iu->ttuv_); \ - checkliveness(L,io); } - - -/* -** Description of an upvalue for function prototypes -*/ -typedef struct Upvaldesc { - TString *name; /* upvalue name (for debug information) */ - lu_byte instack; /* whether it is in stack (register) */ - lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ -} Upvaldesc; - - -/* -** Description of a local variable for function prototypes -** (used for debug information) -*/ -typedef struct LocVar { - TString *varname; - int startpc; /* first point where variable is active */ - int endpc; /* first point where variable is dead */ -} LocVar; - - -/* -** Function Prototypes -*/ -typedef struct Proto { - CommonHeader; - lu_byte numparams; /* number of fixed parameters */ - lu_byte is_vararg; - lu_byte maxstacksize; /* number of registers needed by this function */ - int sizeupvalues; /* size of 'upvalues' */ - int sizek; /* size of 'k' */ - int sizecode; - int sizelineinfo; - int sizep; /* size of 'p' */ - int sizelocvars; - int linedefined; /* debug information */ - int lastlinedefined; /* debug information */ - TValue *k; /* constants used by the function */ - Instruction *code; /* opcodes */ - struct Proto **p; /* functions defined inside the function */ - int *lineinfo; /* map from opcodes to source lines (debug information) */ - LocVar *locvars; /* information about local variables (debug information) */ - Upvaldesc *upvalues; /* upvalue information */ - struct LClosure *cache; /* last-created closure with this prototype */ - TString *source; /* used for debug information */ - GCObject *gclist; -} Proto; - - - -/* -** Lua Upvalues -*/ -typedef struct UpVal UpVal; - - -/* -** Closures -*/ - -#define ClosureHeader \ - CommonHeader; lu_byte nupvalues; GCObject *gclist - -typedef struct CClosure { - ClosureHeader; - lua_CFunction f; - TValue upvalue[1]; /* list of upvalues */ -} CClosure; - - -typedef struct LClosure { - ClosureHeader; - struct Proto *p; - UpVal *upvals[1]; /* list of upvalues */ -} LClosure; - - -typedef union Closure { - CClosure c; - LClosure l; -} Closure; - - -#define isLfunction(o) ttisLclosure(o) - -#define getproto(o) (clLvalue(o)->p) - - -/* -** Tables -*/ - -typedef union TKey { - struct { - TValuefields; - int next; /* for chaining (offset for next node) */ - } nk; - TValue tvk; -} TKey; - - -/* copy a value into a key without messing up field 'next' */ -#define setnodekey(L,key,obj) \ - { TKey *k_=(key); const TValue *io_=(obj); \ - k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ - (void)L; checkliveness(L,io_); } - - -typedef struct Node { - TValue i_val; - TKey i_key; -} Node; - - -typedef struct Table { - CommonHeader; - lu_byte flags; /* 1<

lsizenode)) - - -/* -** (address of) a fixed nil value -*/ -#define luaO_nilobject (&luaO_nilobject_) - - -LUAI_DDEC const TValue luaO_nilobject_; - -/* size of buffer for 'luaO_utf8esc' function */ -#define UTF8BUFFSZ 8 - -LUAI_FUNC int luaO_int2fb (unsigned int x); -LUAI_FUNC int luaO_fb2int (int x); -LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); -LUAI_FUNC int luaO_ceillog2 (unsigned int x); -LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, - const TValue *p2, TValue *res); -LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); -LUAI_FUNC int luaO_hexavalue (int c); -LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj); -LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, - va_list argp); -LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); -LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); - - -#endif - +/* +** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include + + +#include "llimits.h" +#include "lua.h" + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ + +/* +** number of all possible tags (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTAGS (LUA_TPROTO + 2) + + +/* +** tags for Tagged Values have the following use of bits: +** bits 0-3: actual tag (a LUA_T* value) +** bits 4-5: variant bits +** bit 6: whether value is collectable +*/ + + +/* +** LUA_TFUNCTION variants: +** 0 - Lua function +** 1 - light C function +** 2 - regular C function (closure) +*/ + +/* Variant tags for functions */ +#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ +#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ +#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ + + +/* Variant tags for strings */ +#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ +#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ + + +/* Variant tags for numbers */ +#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ +#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) + + +/* +** Common type for all collectable objects +*/ +typedef struct GCObject GCObject; + + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + + +/* +** Common type has only the common header +*/ +struct GCObject { + CommonHeader; +}; + + + + +/* +** Tagged Values. This is the basic representation of values in Lua, +** an actual value plus a tag with its type. +*/ + +/* +** Union of all Lua values +*/ +typedef union Value { + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ +} Value; + + +#define TValuefields Value value_; int tt_ + + +typedef struct lua_TValue { + TValuefields; +} TValue; + + + +/* macro defining a nil value */ +#define NILCONSTANT {NULL}, LUA_TNIL + + +#define val_(o) ((o)->value_) + + +/* raw type tag of a TValue */ +#define rttype(o) ((o)->tt_) + +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + +/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ +#define ttype(o) (rttype(o) & 0x3F) + +/* type tag of a TValue with no variants (bits 0-3) */ +#define ttnov(o) (novariant(rttype(o))) + + +/* Macros to test type */ +#define checktag(o,t) (rttype(o) == (t)) +#define checktype(o,t) (ttnov(o) == (t)) +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_TNUMFLT) +#define ttisinteger(o) checktag((o), LUA_TNUMINT) +#define ttisnil(o) checktag((o), LUA_TNIL) +#define ttisboolean(o) checktag((o), LUA_TBOOLEAN) +#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) +#define ttisstring(o) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) +#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) +#define ttisfunction(o) checktype(o, LUA_TFUNCTION) +#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) +#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) +#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) +#define ttislcf(o) checktag((o), LUA_TLCF) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) +#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) +#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) + + +/* Macros to access values */ +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) +#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) +#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) +#define fvalue(o) check_exp(ttislcf(o), val_(o).f) +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) +#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) +/* a dead value may get the 'gc' field, but cannot access its contents */ +#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + + +#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) + + +/* Macros for internal tests */ +#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) + +#define checkliveness(L,obj) \ + lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) + + +/* Macros to set values */ +#define settt_(o,t) ((o)->tt_=(t)) + +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } + +#define setnilvalue(obj) settt_(obj, LUA_TNIL) + +#define setfvalue(obj,x) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } + +#define setpvalue(obj,x) \ + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } + +#define setbvalue(obj,x) \ + { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } + +#define setgcovalue(L,obj,x) \ + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } + +#define setsvalue(L,obj,x) \ + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } + +#define setuvalue(L,obj,x) \ + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(L,io); } + +#define setthvalue(L,obj,x) \ + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ + checkliveness(L,io); } + +#define setclLvalue(L,obj,x) \ + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ + checkliveness(L,io); } + +#define setclCvalue(L,obj,x) \ + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ + checkliveness(L,io); } + +#define sethvalue(L,obj,x) \ + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(L,io); } + +#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) + + + +#define setobj(L,obj1,obj2) \ + { TValue *io1=(obj1); *io1 = *(obj2); \ + (void)L; checkliveness(L,io1); } + + +/* +** different types of assignments, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue +/* from table to same table */ +#define setobjt2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +/* to table (define it as an expression to be used in macros) */ +#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) + + + + +/* +** {====================================================== +** types and prototypes +** ======================================================= +*/ + + +typedef TValue *StkId; /* index to stack elements */ + + + + +/* +** Header for string value; string bytes follow the end of this structure +** (aligned according to 'UTString'; see next). +*/ +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; +} TString; + + +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UTString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + TString tsv; +} UTString; + + +/* +** Get the actual string (array of bytes) from a 'TString'. +** (Access to 'extra' ensures that value is really a 'TString'.) +*/ +#define getstr(ts) \ + check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) + + +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) + +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) + +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) + + +/* +** Header for userdata; memory area follows the end of this structure +** (aligned according to 'UUdata'; see next). +*/ +typedef struct Udata { + CommonHeader; + lu_byte ttuv_; /* user value's tag */ + struct Table *metatable; + size_t len; /* number of bytes */ + union Value user_; /* user value */ +} Udata; + + +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UUdata { + L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ + Udata uv; +} UUdata; + + +/* +** Get the address of memory block inside 'Udata'. +** (Access to 'ttuv_' ensures that value is really a 'Udata'.) +*/ +#define getudatamem(u) \ + check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) + +#define setuservalue(L,u,o) \ + { const TValue *io=(o); Udata *iu = (u); \ + iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ + checkliveness(L,io); } + + +#define getuservalue(L,u,o) \ + { TValue *io=(o); const Udata *iu = (u); \ + io->value_ = iu->user_; settt_(io, iu->ttuv_); \ + checkliveness(L,io); } + + +/* +** Description of an upvalue for function prototypes +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + lu_byte instack; /* whether it is in stack (register) */ + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ +} Upvaldesc; + + +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + lu_byte numparams; /* number of fixed parameters */ + lu_byte is_vararg; + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ + TValue *k; /* constants used by the function */ + Instruction *code; /* opcodes */ + struct Proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines (debug information) */ + LocVar *locvars; /* information about local variables (debug information) */ + Upvaldesc *upvalues; /* upvalue information */ + struct LClosure *cache; /* last-created closure with this prototype */ + TString *source; /* used for debug information */ + GCObject *gclist; +} Proto; + + + +/* +** Lua Upvalues +*/ +typedef struct UpVal UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; /* list of upvalues */ +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; /* list of upvalues */ +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define isLfunction(o) ttisLclosure(o) + +#define getproto(o) (clLvalue(o)->p) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + int next; /* for chaining (offset for next node) */ + } nk; + TValue tvk; +} TKey; + + +/* copy a value into a key without messing up field 'next' */ +#define setnodekey(L,key,obj) \ + { TKey *k_=(key); const TValue *io_=(obj); \ + k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ + (void)L; checkliveness(L,io_); } + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

lsizenode)) + + +/* +** (address of) a fixed nil value +*/ +#define luaO_nilobject (&luaO_nilobject_) + + +LUAI_DDEC const TValue luaO_nilobject_; + +/* size of buffer for 'luaO_utf8esc' function */ +#define UTF8BUFFSZ 8 + +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); +LUAI_FUNC int luaO_ceillog2 (unsigned int x); +LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, + const TValue *p2, TValue *res); +LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); +LUAI_FUNC int luaO_hexavalue (int c); +LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/libs/lua/include/lopcodes.h b/libs/lua/include/lopcodes.h index 6feaa1cd..f25e24da 100644 --- a/libs/lua/include/lopcodes.h +++ b/libs/lua/include/lopcodes.h @@ -1,297 +1,297 @@ -/* -** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#ifndef lopcodes_h -#define lopcodes_h - -#include "llimits.h" - - -/*=========================================================================== - We assume that instructions are unsigned numbers. - All instructions have an opcode in the first 6 bits. - Instructions can have the following fields: - 'A' : 8 bits - 'B' : 9 bits - 'C' : 9 bits - 'Ax' : 26 bits ('A', 'B', and 'C' together) - 'Bx' : 18 bits ('B' and 'C' together) - 'sBx' : signed Bx - - A signed argument is represented in excess K; that is, the number - value is the unsigned value minus K. K is exactly the maximum value - for that argument (so that -max is represented by 0, and +max is - represented by 2*max), which is half the maximum for the corresponding - unsigned argument. -===========================================================================*/ - - -enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ - - -/* -** size and position of opcode arguments. -*/ -#define SIZE_C 9 -#define SIZE_B 9 -#define SIZE_Bx (SIZE_C + SIZE_B) -#define SIZE_A 8 -#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) - -#define SIZE_OP 6 - -#define POS_OP 0 -#define POS_A (POS_OP + SIZE_OP) -#define POS_C (POS_A + SIZE_A) -#define POS_B (POS_C + SIZE_C) -#define POS_Bx POS_C -#define POS_Ax POS_A - - -/* -** limits for opcode arguments. -** we use (signed) int to manipulate most arguments, -** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) -*/ -#if SIZE_Bx < LUAI_BITSINT-1 -#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ -#else -#define MAXARG_Bx MAX_INT -#define MAXARG_sBx MAX_INT -#endif - -#if SIZE_Ax < LUAI_BITSINT-1 -#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) -#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ - ((cast(Instruction, o)<>pos) & MASK1(size,0))) -#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ - ((cast(Instruction, v)<> RK(C) */ -OP_UNM,/* A B R(A) := -R(B) */ -OP_BNOT,/* A B R(A) := ~R(B) */ -OP_NOT,/* A B R(A) := not R(B) */ -OP_LEN,/* A B R(A) := length of R(B) */ - -OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ - -OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ -OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ -OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ -OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ - -OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ - -OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ -OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ -OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ - -OP_FORLOOP,/* A sBx R(A)+=R(A+2); - if R(A) > 4) & 3)) -#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) -#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) -#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) - - -LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ - - -/* number of list items to accumulate before a SETLIST instruction */ -#define LFIELDS_PER_FLUSH 50 - - -#endif +/* +** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + 'A' : 8 bits + 'B' : 9 bits + 'C' : 9 bits + 'Ax' : 26 bits ('A', 'B', and 'C' together) + 'Bx' : 18 bits ('B' and 'C' together) + 'sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C +#define POS_Ax POS_A + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + +#if SIZE_Ax < LUAI_BITSINT-1 +#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>pos) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<> RK(C) */ +OP_UNM,/* A B R(A) := -R(B) */ +OP_BNOT,/* A B R(A) := ~R(B) */ +OP_NOT,/* A B R(A) := not R(B) */ +OP_LEN,/* A B R(A) := length of R(B) */ + +OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ +OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ +OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ +OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) > 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) + + +LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/libs/lua/include/lparser.h b/libs/lua/include/lparser.h index f45b23cb..19931fe4 100644 --- a/libs/lua/include/lparser.h +++ b/libs/lua/include/lparser.h @@ -1,133 +1,133 @@ -/* -** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - -#ifndef lparser_h -#define lparser_h - -#include "llimits.h" -#include "lobject.h" -#include "lzio.h" - - -/* -** Expression and variable descriptor. -** Code generation for variables and expressions can be delayed to allow -** optimizations; An 'expdesc' structure describes a potentially-delayed -** variable/expression. It has a description of its "main" value plus a -** list of conditional jumps that can also produce its value (generated -** by short-circuit operators 'and'/'or'). -*/ - -/* kinds of variables/expressions */ -typedef enum { - VVOID, /* when 'expdesc' describes the last expression a list, - this kind means an empty list (so, no expression) */ - VNIL, /* constant nil */ - VTRUE, /* constant true */ - VFALSE, /* constant false */ - VK, /* constant in 'k'; info = index of constant in 'k' */ - VKFLT, /* floating constant; nval = numerical float value */ - VKINT, /* integer constant; nval = numerical integer value */ - VNONRELOC, /* expression has its value in a fixed register; - info = result register */ - VLOCAL, /* local variable; info = local register */ - VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ - VINDEXED, /* indexed variable; - ind.vt = whether 't' is register or upvalue; - ind.t = table register or upvalue; - ind.idx = key's R/K index */ - VJMP, /* expression is a test/comparison; - info = pc of corresponding jump instruction */ - VRELOCABLE, /* expression can put result in any register; - info = instruction pc */ - VCALL, /* expression is a function call; info = instruction pc */ - VVARARG /* vararg expression; info = instruction pc */ -} expkind; - - -#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) -#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) - -typedef struct expdesc { - expkind k; - union { - lua_Integer ival; /* for VKINT */ - lua_Number nval; /* for VKFLT */ - int info; /* for generic use */ - struct { /* for indexed variables (VINDEXED) */ - short idx; /* index (R/K) */ - lu_byte t; /* table (register or upvalue) */ - lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ - } ind; - } u; - int t; /* patch list of 'exit when true' */ - int f; /* patch list of 'exit when false' */ -} expdesc; - - -/* description of active local variable */ -typedef struct Vardesc { - short idx; /* variable index in stack */ -} Vardesc; - - -/* description of pending goto statements and label statements */ -typedef struct Labeldesc { - TString *name; /* label identifier */ - int pc; /* position in code */ - int line; /* line where it appeared */ - lu_byte nactvar; /* local level where it appears in current block */ -} Labeldesc; - - -/* list of labels or gotos */ -typedef struct Labellist { - Labeldesc *arr; /* array */ - int n; /* number of entries in use */ - int size; /* array size */ -} Labellist; - - -/* dynamic structures used by the parser */ -typedef struct Dyndata { - struct { /* list of active local variables */ - Vardesc *arr; - int n; - int size; - } actvar; - Labellist gt; /* list of pending gotos */ - Labellist label; /* list of active labels */ -} Dyndata; - - -/* control of blocks */ -struct BlockCnt; /* defined in lparser.c */ - - -/* state needed to generate code for a given function */ -typedef struct FuncState { - Proto *f; /* current function header */ - struct FuncState *prev; /* enclosing function */ - struct LexState *ls; /* lexical state */ - struct BlockCnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to 'ncode') */ - int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to 'pc' */ - int nk; /* number of elements in 'k' */ - int np; /* number of elements in 'p' */ - int firstlocal; /* index of first local var (in Dyndata array) */ - short nlocvars; /* number of elements in 'f->locvars' */ - lu_byte nactvar; /* number of active local variables */ - lu_byte nups; /* number of upvalues */ - lu_byte freereg; /* first free register */ -} FuncState; - - -LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); - - -#endif +/* +** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* +** Expression and variable descriptor. +** Code generation for variables and expressions can be delayed to allow +** optimizations; An 'expdesc' structure describes a potentially-delayed +** variable/expression. It has a description of its "main" value plus a +** list of conditional jumps that can also produce its value (generated +** by short-circuit operators 'and'/'or'). +*/ + +/* kinds of variables/expressions */ +typedef enum { + VVOID, /* when 'expdesc' describes the last expression a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; nval = numerical integer value */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; info = local register */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VINDEXED, /* indexed variable; + ind.vt = whether 't' is register or upvalue; + ind.t = table register or upvalue; + ind.idx = key's R/K index */ + VJMP, /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOCABLE, /* expression can put result in any register; + info = instruction pc */ + VCALL, /* expression is a function call; info = instruction pc */ + VVARARG /* vararg expression; info = instruction pc */ +} expkind; + + +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) +#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) + +typedef struct expdesc { + expkind k; + union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + int info; /* for generic use */ + struct { /* for indexed variables (VINDEXED) */ + short idx; /* index (R/K) */ + lu_byte t; /* table (register or upvalue) */ + lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ + } ind; + } u; + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ +} expdesc; + + +/* description of active local variable */ +typedef struct Vardesc { + short idx; /* variable index in stack */ +} Vardesc; + + +/* description of pending goto statements and label statements */ +typedef struct Labeldesc { + TString *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* local level where it appears in current block */ +} Labeldesc; + + +/* list of labels or gotos */ +typedef struct Labellist { + Labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} Labellist; + + +/* dynamic structures used by the parser */ +typedef struct Dyndata { + struct { /* list of active local variables */ + Vardesc *arr; + int n; + int size; + } actvar; + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ +} Dyndata; + + +/* control of blocks */ +struct BlockCnt; /* defined in lparser.c */ + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to 'ncode') */ + int lasttarget; /* 'label' of last 'jump label' */ + int jpc; /* list of pending jumps to 'pc' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + short nlocvars; /* number of elements in 'f->locvars' */ + lu_byte nactvar; /* number of active local variables */ + lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ +} FuncState; + + +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); + + +#endif diff --git a/libs/lua/include/lprefix.h b/libs/lua/include/lprefix.h index 9a749a3f..c1f7b7ef 100644 --- a/libs/lua/include/lprefix.h +++ b/libs/lua/include/lprefix.h @@ -1,45 +1,45 @@ -/* -** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $ -** Definitions for Lua code that must come before any other header file -** See Copyright Notice in lua.h -*/ - -#ifndef lprefix_h -#define lprefix_h - - -/* -** Allows POSIX/XSI stuff -*/ -#if !defined(LUA_USE_C89) /* { */ - -#if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE 600 -#elif _XOPEN_SOURCE == 0 -#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ -#endif - -/* -** Allows manipulation of large files in gcc and some other compilers -*/ -#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 -#endif - -#endif /* } */ - - -/* -** Windows stuff -*/ -#if defined(_WIN32) /* { */ - -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ -#endif - -#endif /* } */ - -#endif - +/* +** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/libs/lua/include/lstate.h b/libs/lua/include/lstate.h index 56b37410..588963df 100644 --- a/libs/lua/include/lstate.h +++ b/libs/lua/include/lstate.h @@ -1,253 +1,253 @@ -/* -** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - -#ifndef lstate_h -#define lstate_h - -#include "lua.h" - -#include "lobject.h" -#include "ltm.h" -#include "lzio.h" - - -/* - -** Some notes about garbage-collected objects: All objects in Lua must -** be kept somehow accessible until being freed, so all objects always -** belong to one (and only one) of these lists, using field 'next' of -** the 'CommonHeader' for the link: -** -** 'allgc': all objects not marked for finalization; -** 'finobj': all objects marked for finalization; -** 'tobefnz': all objects ready to be finalized; -** 'fixedgc': all objects that are not to be collected (currently -** only small strings, such as reserved words). -** -** Moreover, there is another set of lists that control gray objects. -** These lists are linked by fields 'gclist'. (All objects that -** can become gray have such a field. The field is not the same -** in all objects, but it always has this name.) Any gray object -** must belong to one of these lists, and all objects in these lists -** must be gray: -** -** 'gray': regular gray objects, still waiting to be visited. -** 'grayagain': objects that must be revisited at the atomic phase. -** That includes -** - black objects got in a write barrier; -** - all kinds of weak tables during propagation phase; -** - all threads. -** 'weak': tables with weak values to be cleared; -** 'ephemeron': ephemeron tables with white->white entries; -** 'allweak': tables with weak keys and/or weak values to be cleared. -** The last three lists are used only during the atomic phase. - -*/ - - -struct lua_longjmp; /* defined in ldo.c */ - - -/* -** Atomic type (relative to signals) to better ensure that 'lua_sethook' -** is thread safe -*/ -#if !defined(l_signalT) -#include -#define l_signalT sig_atomic_t -#endif - - -/* extra stack space to handle TM calls and some other extras */ -#define EXTRA_STACK 5 - - -#define BASIC_STACK_SIZE (2*LUA_MINSTACK) - - -/* kinds of Garbage Collection */ -#define KGC_NORMAL 0 -#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ - - -typedef struct stringtable { - TString **hash; - int nuse; /* number of elements */ - int size; -} stringtable; - - -/* -** Information about a call. -** When a thread yields, 'func' is adjusted to pretend that the -** top function has only the yielded values in its stack; in that -** case, the actual 'func' value is saved in field 'extra'. -** When a function calls another with a continuation, 'extra' keeps -** the function index so that, in case of errors, the continuation -** function can be called with the correct top. -*/ -typedef struct CallInfo { - StkId func; /* function index in the stack */ - StkId top; /* top for this function */ - struct CallInfo *previous, *next; /* dynamic call link */ - union { - struct { /* only for Lua functions */ - StkId base; /* base for this function */ - const Instruction *savedpc; - } l; - struct { /* only for C functions */ - lua_KFunction k; /* continuation in case of yields */ - ptrdiff_t old_errfunc; - lua_KContext ctx; /* context info. in case of yields */ - } c; - } u; - ptrdiff_t extra; - short nresults; /* expected number of results from this function */ - unsigned short callstatus; -} CallInfo; - - -/* -** Bits in CallInfo status -*/ -#define CIST_OAH (1<<0) /* original value of 'allowhook' */ -#define CIST_LUA (1<<1) /* call is running a Lua function */ -#define CIST_HOOKED (1<<2) /* call is running a debug hook */ -#define CIST_FRESH (1<<3) /* call is running on a fresh invocation - of luaV_execute */ -#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ -#define CIST_TAIL (1<<5) /* call was tail called */ -#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ -#define CIST_LEQ (1<<7) /* using __lt for __le */ -#define CIST_FIN (1<<8) /* call is running a finalizer */ - -#define isLua(ci) ((ci)->callstatus & CIST_LUA) - -/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ -#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) -#define getoah(st) ((st) & CIST_OAH) - - -/* -** 'global state', shared by all threads of this state -*/ -typedef struct global_State { - lua_Alloc frealloc; /* function to reallocate memory */ - void *ud; /* auxiliary data to 'frealloc' */ - l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ - l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - lu_mem GCmemtrav; /* memory traversed by the GC */ - lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ - stringtable strt; /* hash table for strings */ - TValue l_registry; - unsigned int seed; /* randomized seed for hashes */ - lu_byte currentwhite; - lu_byte gcstate; /* state of garbage collector */ - lu_byte gckind; /* kind of GC running */ - lu_byte gcrunning; /* true if GC is running */ - GCObject *allgc; /* list of all collectable objects */ - GCObject **sweepgc; /* current position of sweep in list */ - GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject *gray; /* list of gray objects */ - GCObject *grayagain; /* list of objects to be traversed atomically */ - GCObject *weak; /* list of tables with weak values */ - GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ - GCObject *allweak; /* list of all-weak tables */ - GCObject *tobefnz; /* list of userdata to be GC */ - GCObject *fixedgc; /* list of objects not to be collected */ - struct lua_State *twups; /* list of threads with open upvalues */ - unsigned int gcfinnum; /* number of finalizers to call in each GC step */ - int gcpause; /* size of pause between successive GCs */ - int gcstepmul; /* GC 'granularity' */ - lua_CFunction panic; /* to be called in unprotected errors */ - struct lua_State *mainthread; - const lua_Number *version; /* pointer to version number */ - TString *memerrmsg; /* memory-error message */ - TString *tmname[TM_N]; /* array with tag-method names */ - struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ - TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ -} global_State; - - -/* -** 'per thread' state -*/ -struct lua_State { - CommonHeader; - unsigned short nci; /* number of items in 'ci' list */ - lu_byte status; - StkId top; /* first free slot in the stack */ - global_State *l_G; - CallInfo *ci; /* call info for current function */ - const Instruction *oldpc; /* last pc traced */ - StkId stack_last; /* last free slot in the stack */ - StkId stack; /* stack base */ - UpVal *openupval; /* list of open upvalues in this stack */ - GCObject *gclist; - struct lua_State *twups; /* list of threads with open upvalues */ - struct lua_longjmp *errorJmp; /* current error recover point */ - CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ - volatile lua_Hook hook; - ptrdiff_t errfunc; /* current error handling function (stack index) */ - int stacksize; - int basehookcount; - int hookcount; - unsigned short nny; /* number of non-yieldable calls in stack */ - unsigned short nCcalls; /* number of nested C calls */ - l_signalT hookmask; - lu_byte allowhook; -}; - - -#define G(L) (L->l_G) - - -/* -** Union of all collectable objects (only for conversions) -*/ -union GCUnion { - GCObject gc; /* common header */ - struct TString ts; - struct Udata u; - union Closure cl; - struct Table h; - struct Proto p; - struct lua_State th; /* thread */ -}; - - -#define cast_u(o) cast(union GCUnion *, (o)) - -/* macros to convert a GCObject into a specific value */ -#define gco2ts(o) \ - check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) -#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) -#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) -#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) -#define gco2cl(o) \ - check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) -#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) -#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) -#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) - - -/* macro to convert a Lua object into a GCObject */ -#define obj2gco(v) \ - check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) - - -/* actual number of total bytes allocated */ -#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) - -LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); -LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); -LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); -LUAI_FUNC void luaE_freeCI (lua_State *L); -LUAI_FUNC void luaE_shrinkCI (lua_State *L); - - -#endif - +/* +** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + +/* + +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: +** +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). +** +** Moreover, there is another set of lists that control gray objects. +** These lists are linked by fields 'gclist'. (All objects that +** can become gray have such a field. The field is not the same +** in all objects, but it always has this name.) Any gray object +** must belong to one of these lists, and all objects in these lists +** must be gray: +** +** 'gray': regular gray objects, still waiting to be visited. +** 'grayagain': objects that must be revisited at the atomic phase. +** That includes +** - black objects got in a write barrier; +** - all kinds of weak tables during propagation phase; +** - all threads. +** 'weak': tables with weak values to be cleared; +** 'ephemeron': ephemeron tables with white->white entries; +** 'allweak': tables with weak keys and/or weak values to be cleared. +** The last three lists are used only during the atomic phase. + +*/ + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* +** Atomic type (relative to signals) to better ensure that 'lua_sethook' +** is thread safe +*/ +#if !defined(l_signalT) +#include +#define l_signalT sig_atomic_t +#endif + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ + + +typedef struct stringtable { + TString **hash; + int nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** Information about a call. +** When a thread yields, 'func' is adjusted to pretend that the +** top function has only the yielded values in its stack; in that +** case, the actual 'func' value is saved in field 'extra'. +** When a function calls another with a continuation, 'extra' keeps +** the function index so that, in case of errors, the continuation +** function can be called with the correct top. +*/ +typedef struct CallInfo { + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union { + struct { /* only for Lua functions */ + StkId base; /* base for this function */ + const Instruction *savedpc; + } l; + struct { /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + ptrdiff_t extra; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; +} CallInfo; + + +/* +** Bits in CallInfo status +*/ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_HOOKED (1<<2) /* call is running a debug hook */ +#define CIST_FRESH (1<<3) /* call is running on a fresh invocation + of luaV_execute */ +#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_LEQ (1<<7) /* using __lt for __le */ +#define CIST_FIN (1<<8) /* call is running a finalizer */ + +#define isLua(ci) ((ci)->callstatus & CIST_LUA) + +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + + +/* +** 'global state', shared by all threads of this state +*/ +typedef struct global_State { + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ + lu_mem GCmemtrav; /* memory traversed by the GC */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + stringtable strt; /* hash table for strings */ + TValue l_registry; + unsigned int seed; /* randomized seed for hashes */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ + lu_byte gcrunning; /* true if GC is running */ + GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ + GCObject *finobj; /* list of collectable objects with finalizers */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + GCObject *fixedgc; /* list of objects not to be collected */ + struct lua_State *twups; /* list of threads with open upvalues */ + unsigned int gcfinnum; /* number of finalizers to call in each GC step */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC 'granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + struct lua_State *mainthread; + const lua_Number *version; /* pointer to version number */ + TString *memerrmsg; /* memory-error message */ + TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ +} global_State; + + +/* +** 'per thread' state +*/ +struct lua_State { + CommonHeader; + unsigned short nci; /* number of items in 'ci' list */ + lu_byte status; + StkId top; /* first free slot in the stack */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *oldpc; /* last pc traced */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ + int stacksize; + int basehookcount; + int hookcount; + unsigned short nny; /* number of non-yieldable calls in stack */ + unsigned short nCcalls; /* number of nested C calls */ + l_signalT hookmask; + lu_byte allowhook; +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects (only for conversions) +*/ +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct lua_State th; /* thread */ +}; + + +#define cast_u(o) cast(union GCUnion *, (o)) + +/* macros to convert a GCObject into a specific value */ +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) + + +/* macro to convert a Lua object into a GCObject */ +#define obj2gco(v) \ + check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) + + +/* actual number of total bytes allocated */ +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) + +LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); + + +#endif + diff --git a/libs/lua/include/lstring.h b/libs/lua/include/lstring.h index d612abd3..afc3eccf 100644 --- a/libs/lua/include/lstring.h +++ b/libs/lua/include/lstring.h @@ -1,49 +1,49 @@ -/* -** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $ -** String table (keep all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - -#ifndef lstring_h -#define lstring_h - -#include "lgc.h" -#include "lobject.h" -#include "lstate.h" - - -#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) - -#define sizeludata(l) (sizeof(union UUdata) + (l)) -#define sizeudata(u) sizeludata((u)->len) - -#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ - (sizeof(s)/sizeof(char))-1)) - - -/* -** test whether a string is a reserved word -*/ -#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) - - -/* -** equality for short strings, which are always internalized -*/ -#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) - - -LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); -LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); -LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); -LUAI_FUNC void luaS_resize (lua_State *L, int newsize); -LUAI_FUNC void luaS_clearcache (global_State *g); -LUAI_FUNC void luaS_init (lua_State *L); -LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); -LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); -LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); -LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); -LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); - - -#endif +/* +** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) + +#define sizeludata(l) (sizeof(union UUdata) + (l)) +#define sizeudata(u) sizeludata((u)->len) + +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + + +/* +** test whether a string is a reserved word +*/ +#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) + + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); + + +#endif diff --git a/libs/lua/include/ltable.h b/libs/lua/include/ltable.h index 92db0ac7..422ea374 100644 --- a/libs/lua/include/ltable.h +++ b/libs/lua/include/ltable.h @@ -1,66 +1,66 @@ -/* -** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - -#ifndef ltable_h -#define ltable_h - -#include "lobject.h" - - -#define gnode(t,i) (&(t)->node[i]) -#define gval(n) (&(n)->i_val) -#define gnext(n) ((n)->i_key.nk.next) - - -/* 'const' to avoid wrong writings that can mess up field 'next' */ -#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) - -/* -** writable version of 'gkey'; allows updates to individual fields, -** but not to the whole (which has incompatible type) -*/ -#define wgkey(n) (&(n)->i_key.nk) - -#define invalidateTMcache(t) ((t)->flags = 0) - - -/* true when 't' is using 'dummynode' as its hash part */ -#define isdummy(t) ((t)->lastfree == NULL) - - -/* allocated size for hash nodes */ -#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) - - -/* returns the key, given the value of a table entry */ -#define keyfromval(v) \ - (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) - - -LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); -LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, - TValue *value); -LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); -LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); -LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); -LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC Table *luaH_new (lua_State *L); -LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize); -LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); -LUAI_FUNC void luaH_free (lua_State *L, Table *t); -LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); -LUAI_FUNC lua_Unsigned luaH_getn (Table *t); - - -#if defined(LUA_DEBUG) -LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); -LUAI_FUNC int luaH_isdummy (const Table *t); -#endif - - -#endif +/* +** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define gnode(t,i) (&(t)->node[i]) +#define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.nk.next) + + +/* 'const' to avoid wrong writings that can mess up field 'next' */ +#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) + +/* +** writable version of 'gkey'; allows updates to individual fields, +** but not to the whole (which has incompatible type) +*/ +#define wgkey(n) (&(n)->i_key.nk) + +#define invalidateTMcache(t) ((t)->flags = 0) + + +/* true when 't' is using 'dummynode' as its hash part */ +#define isdummy(t) ((t)->lastfree == NULL) + + +/* allocated size for hash nodes */ +#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) + + +/* returns the key, given the value of a table entry */ +#define keyfromval(v) \ + (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) + + +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); + + +#if defined(LUA_DEBUG) +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC int luaH_isdummy (const Table *t); +#endif + + +#endif diff --git a/libs/lua/include/ltm.h b/libs/lua/include/ltm.h index 8170688d..1d99dc32 100644 --- a/libs/lua/include/ltm.h +++ b/libs/lua/include/ltm.h @@ -1,76 +1,76 @@ -/* -** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $ -** Tag methods -** See Copyright Notice in lua.h -*/ - -#ifndef ltm_h -#define ltm_h - - -#include "lobject.h" - - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER TM" and "ORDER OP" -*/ -typedef enum { - TM_INDEX, - TM_NEWINDEX, - TM_GC, - TM_MODE, - TM_LEN, - TM_EQ, /* last tag method with fast access */ - TM_ADD, - TM_SUB, - TM_MUL, - TM_MOD, - TM_POW, - TM_DIV, - TM_IDIV, - TM_BAND, - TM_BOR, - TM_BXOR, - TM_SHL, - TM_SHR, - TM_UNM, - TM_BNOT, - TM_LT, - TM_LE, - TM_CONCAT, - TM_CALL, - TM_N /* number of elements in the enum */ -} TMS; - - - -#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ - ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) - -#define fasttm(l,et,e) gfasttm(G(l), et, e) - -#define ttypename(x) luaT_typenames_[(x) + 1] - -LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; - - -LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); - -LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); -LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, - TMS event); -LUAI_FUNC void luaT_init (lua_State *L); - -LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres); -LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event); -LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, - const TValue *p2, TMS event); - - - -#endif +/* +** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" and "ORDER OP" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_LEN, + TM_EQ, /* last tag method with fast access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_MOD, + TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, + TM_UNM, + TM_BNOT, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +#define ttypename(x) luaT_typenames_[(x) + 1] + +LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; + + +LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres); +LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); + + + +#endif diff --git a/libs/lua/include/lua.h b/libs/lua/include/lua.h index c236e360..69295d92 100644 --- a/libs/lua/include/lua.h +++ b/libs/lua/include/lua.h @@ -1,486 +1,486 @@ -/* -** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $ -** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) -** See Copyright Notice at the end of this file -*/ - - -#ifndef lua_h -#define lua_h - -#include -#include - - -#include "luaconf.h" - - -#define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "3" -#define LUA_VERSION_NUM 503 -#define LUA_VERSION_RELEASE "5" - -#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" - - -/* mark for precompiled code ('Lua') */ -#define LUA_SIGNATURE "\x1bLua" - -/* option for multiple returns in 'lua_pcall' and 'lua_call' */ -#define LUA_MULTRET (-1) - - -/* -** Pseudo-indices -** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty -** space after that to help overflow detection) -*/ -#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) -#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) - - -/* thread status */ -#define LUA_OK 0 -#define LUA_YIELD 1 -#define LUA_ERRRUN 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRGCMM 5 -#define LUA_ERRERR 6 - - -typedef struct lua_State lua_State; - - -/* -** basic types -*/ -#define LUA_TNONE (-1) - -#define LUA_TNIL 0 -#define LUA_TBOOLEAN 1 -#define LUA_TLIGHTUSERDATA 2 -#define LUA_TNUMBER 3 -#define LUA_TSTRING 4 -#define LUA_TTABLE 5 -#define LUA_TFUNCTION 6 -#define LUA_TUSERDATA 7 -#define LUA_TTHREAD 8 - -#define LUA_NUMTAGS 9 - - - -/* minimum Lua stack available to a C function */ -#define LUA_MINSTACK 20 - - -/* predefined values in the registry */ -#define LUA_RIDX_MAINTHREAD 1 -#define LUA_RIDX_GLOBALS 2 -#define LUA_RIDX_LAST LUA_RIDX_GLOBALS - - -/* type of numbers in Lua */ -typedef LUA_NUMBER lua_Number; - - -/* type for integer functions */ -typedef LUA_INTEGER lua_Integer; - -/* unsigned integer type */ -typedef LUA_UNSIGNED lua_Unsigned; - -/* type for continuation-function contexts */ -typedef LUA_KCONTEXT lua_KContext; - - -/* -** Type for C functions registered with Lua -*/ -typedef int (*lua_CFunction) (lua_State *L); - -/* -** Type for continuation functions -*/ -typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); - - -/* -** Type for functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); - - -/* -** Type for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - - - -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif - - -/* -** RCS ident string -*/ -extern const char lua_ident[]; - - -/* -** state manipulation -*/ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); -LUA_API void (lua_close) (lua_State *L); -LUA_API lua_State *(lua_newthread) (lua_State *L); - -LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); - - -LUA_API const lua_Number *(lua_version) (lua_State *L); - - -/* -** basic stack manipulation -*/ -LUA_API int (lua_absindex) (lua_State *L, int idx); -LUA_API int (lua_gettop) (lua_State *L); -LUA_API void (lua_settop) (lua_State *L, int idx); -LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_rotate) (lua_State *L, int idx, int n); -LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, int n); - -LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); - - -/* -** access functions (stack -> C) -*/ - -LUA_API int (lua_isnumber) (lua_State *L, int idx); -LUA_API int (lua_isstring) (lua_State *L, int idx); -LUA_API int (lua_iscfunction) (lua_State *L, int idx); -LUA_API int (lua_isinteger) (lua_State *L, int idx); -LUA_API int (lua_isuserdata) (lua_State *L, int idx); -LUA_API int (lua_type) (lua_State *L, int idx); -LUA_API const char *(lua_typename) (lua_State *L, int tp); - -LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); -LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); -LUA_API int (lua_toboolean) (lua_State *L, int idx); -LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_rawlen) (lua_State *L, int idx); -LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); -LUA_API void *(lua_touserdata) (lua_State *L, int idx); -LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); -LUA_API const void *(lua_topointer) (lua_State *L, int idx); - - -/* -** Comparison and arithmetic functions -*/ - -#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ -#define LUA_OPSUB 1 -#define LUA_OPMUL 2 -#define LUA_OPMOD 3 -#define LUA_OPPOW 4 -#define LUA_OPDIV 5 -#define LUA_OPIDIV 6 -#define LUA_OPBAND 7 -#define LUA_OPBOR 8 -#define LUA_OPBXOR 9 -#define LUA_OPSHL 10 -#define LUA_OPSHR 11 -#define LUA_OPUNM 12 -#define LUA_OPBNOT 13 - -LUA_API void (lua_arith) (lua_State *L, int op); - -#define LUA_OPEQ 0 -#define LUA_OPLT 1 -#define LUA_OPLE 2 - -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); - - -/* -** push functions (C -> stack) -*/ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); -LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); -LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); -LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); -LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); -LUA_API void (lua_pushboolean) (lua_State *L, int b); -LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); -LUA_API int (lua_pushthread) (lua_State *L); - - -/* -** get functions (Lua -> stack) -*/ -LUA_API int (lua_getglobal) (lua_State *L, const char *name); -LUA_API int (lua_gettable) (lua_State *L, int idx); -LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawget) (lua_State *L, int idx); -LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); - -LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); -LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); -LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API int (lua_getuservalue) (lua_State *L, int idx); - - -/* -** set functions (stack -> Lua) -*/ -LUA_API void (lua_setglobal) (lua_State *L, const char *name); -LUA_API void (lua_settable) (lua_State *L, int idx); -LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); -LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API void (lua_setuservalue) (lua_State *L, int idx); - - -/* -** 'load' and 'call' functions (load and run Lua code) -*/ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); -#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) - -LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k); -#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) - -LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); - -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - - -/* -** coroutine functions -*/ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); -LUA_API int (lua_isyieldable) (lua_State *L); - -#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) - - -/* -** garbage-collection function and options -*/ - -#define LUA_GCSTOP 0 -#define LUA_GCRESTART 1 -#define LUA_GCCOLLECT 2 -#define LUA_GCCOUNT 3 -#define LUA_GCCOUNTB 4 -#define LUA_GCSTEP 5 -#define LUA_GCSETPAUSE 6 -#define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 9 - -LUA_API int (lua_gc) (lua_State *L, int what, int data); - - -/* -** miscellaneous functions -*/ - -LUA_API int (lua_error) (lua_State *L); - -LUA_API int (lua_next) (lua_State *L, int idx); - -LUA_API void (lua_concat) (lua_State *L, int n); -LUA_API void (lua_len) (lua_State *L, int idx); - -LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); - -LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - - - -/* -** {============================================================== -** some useful macros -** =============================================================== -*/ - -#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) - -#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) -#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) - -#define lua_pop(L,n) lua_settop(L, -(n)-1) - -#define lua_newtable(L) lua_createtable(L, 0, 0) - -#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) - -#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) - -#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) -#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) -#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) -#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) -#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) -#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) -#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) -#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) - -#define lua_pushliteral(L, s) lua_pushstring(L, "" s) - -#define lua_pushglobaltable(L) \ - ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) - -#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) - - -#define lua_insert(L,idx) lua_rotate(L, (idx), 1) - -#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) - -#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) - -/* }============================================================== */ - - -/* -** {============================================================== -** compatibility macros for unsigned conversions -** =============================================================== -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) -#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) - -#endif -/* }============================================================== */ - -/* -** {====================================================================== -** Debug API -** ======================================================================= -*/ - - -/* -** Event codes -*/ -#define LUA_HOOKCALL 0 -#define LUA_HOOKRET 1 -#define LUA_HOOKLINE 2 -#define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILCALL 4 - - -/* -** Event masks -*/ -#define LUA_MASKCALL (1 << LUA_HOOKCALL) -#define LUA_MASKRET (1 << LUA_HOOKRET) -#define LUA_MASKLINE (1 << LUA_HOOKLINE) -#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) - -typedef struct lua_Debug lua_Debug; /* activation record */ - - -/* Functions to be called by the debugger in specific events */ -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); - - -LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); -LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); -LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); - -LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); -LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, - int fidx2, int n2); - -LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook (lua_gethook) (lua_State *L); -LUA_API int (lua_gethookmask) (lua_State *L); -LUA_API int (lua_gethookcount) (lua_State *L); - - -struct lua_Debug { - int event; - const char *name; /* (n) */ - const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ - const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ - const char *source; /* (S) */ - int currentline; /* (l) */ - int linedefined; /* (S) */ - int lastlinedefined; /* (S) */ - unsigned char nups; /* (u) number of upvalues */ - unsigned char nparams;/* (u) number of parameters */ - char isvararg; /* (u) */ - char istailcall; /* (t) */ - char short_src[LUA_IDSIZE]; /* (S) */ - /* private part */ - struct CallInfo *i_ci; /* active function */ -}; - -/* }====================================================================== */ - - -/****************************************************************************** -* Copyright (C) 1994-2018 Lua.org, PUC-Rio. -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ - - -#endif +/* +** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $ +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "3" +#define LUA_VERSION_NUM 503 +#define LUA_VERSION_RELEASE "5" + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" + + +/* mark for precompiled code ('Lua') */ +#define LUA_SIGNATURE "\x1bLua" + +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** Pseudo-indices +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) +*/ +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) + + +/* thread status */ +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 + + +typedef struct lua_State lua_State; + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + +#define LUA_NUMTAGS 9 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_GLOBALS 2 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* +** RCS ident string +*/ +extern const char lua_ident[]; + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +LUA_API const lua_Number *(lua_version) (lua_State *L); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_absindex) (lua_State *L, int idx); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); +LUA_API int (lua_checkstack) (lua_State *L, int n); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_rawlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +LUA_API int (lua_gettable) (lua_State *L, int idx); +LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API int (lua_getuservalue) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_setglobal) (lua_State *L, const char *name); +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); +LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API void (lua_setuservalue) (lua_State *L, int idx); + + +/* +** 'load' and 'call' functions (load and run Lua code) +*/ +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) + + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 9 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); + +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** {============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) + +#define lua_pushglobaltable(L) \ + ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros for unsigned conversions +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif +/* }============================================================== */ + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILCALL 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debugger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct CallInfo *i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2018 Lua.org, PUC-Rio. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/libs/lua/include/lua.hpp b/libs/lua/include/lua.hpp index ec417f59..6c10bc05 100644 --- a/libs/lua/include/lua.hpp +++ b/libs/lua/include/lua.hpp @@ -1,9 +1,9 @@ -// lua.hpp -// Lua header files for C++ -// <> not supplied automatically because Lua also compiles as C++ - -extern "C" { -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -} +// lua.hpp +// Lua header files for C++ +// <> not supplied automatically because Lua also compiles as C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} diff --git a/libs/lua/include/luaconf.h b/libs/lua/include/luaconf.h index dfd7a10f..04c675d0 100644 --- a/libs/lua/include/luaconf.h +++ b/libs/lua/include/luaconf.h @@ -1,787 +1,787 @@ -/* -** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $ -** Configuration file for Lua -** See Copyright Notice in lua.h -*/ - - -#ifndef luaconf_h -#define luaconf_h - -#include -#include -#include - - -/* -** =================================================================== -** Search for "@@" to find all configurable definitions. -** =================================================================== -*/ - - -/* -** {==================================================================== -** System Configuration: macros to adapt (if needed) Lua to some -** particular platform, for instance compiling it with 32-bit numbers or -** restricting it to C89. -** ===================================================================== -*/ - -/* -@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You -** can also define LUA_32BITS in the make file, but changing here you -** ensure that all software connected to Lua will be compiled with the -** same configuration. -*/ -/* #define LUA_32BITS */ - - -/* -@@ LUA_USE_C89 controls the use of non-ISO-C89 features. -** Define it if you want Lua to avoid the use of a few C99 features -** or Windows-specific features on Windows. -*/ -/* #define LUA_USE_C89 */ - - -/* -** By default, Lua on Windows use (some) specific Windows features -*/ -#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ -#endif - - -#if defined(LUA_USE_WINDOWS) -#define LUA_DL_DLL /* enable support for DLL */ -#define LUA_USE_C89 /* broadly, Windows is C89 */ -#endif - - -#if defined(LUA_USE_LINUX) -#define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ -#define LUA_USE_READLINE /* needs some extra libraries */ -#endif - - -#if defined(LUA_USE_MACOSX) -#define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ -#define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#endif - - -/* -@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for -** C89 ('long' and 'double'); Windows always has '__int64', so it does -** not need to use this case. -*/ -#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) -#define LUA_C89_NUMBERS -#endif - - - -/* -@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. -*/ -/* avoid undefined shifts */ -#if ((INT_MAX >> 15) >> 15) >= 1 -#define LUAI_BITSINT 32 -#else -/* 'int' always must have at least 16 bits */ -#define LUAI_BITSINT 16 -#endif - - -/* -@@ LUA_INT_TYPE defines the type for Lua integers. -@@ LUA_FLOAT_TYPE defines the type for Lua floats. -** Lua should work fine with any mix of these options (if supported -** by your C compiler). The usual configurations are 64-bit integers -** and 'double' (the default), 32-bit integers and 'float' (for -** restricted platforms), and 'long'/'double' (for C compilers not -** compliant with C99, which may not have support for 'long long'). -*/ - -/* predefined options for LUA_INT_TYPE */ -#define LUA_INT_INT 1 -#define LUA_INT_LONG 2 -#define LUA_INT_LONGLONG 3 - -/* predefined options for LUA_FLOAT_TYPE */ -#define LUA_FLOAT_FLOAT 1 -#define LUA_FLOAT_DOUBLE 2 -#define LUA_FLOAT_LONGDOUBLE 3 - -#if defined(LUA_32BITS) /* { */ -/* -** 32-bit integers and 'float' -*/ -#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ -#define LUA_INT_TYPE LUA_INT_INT -#else /* otherwise use 'long' */ -#define LUA_INT_TYPE LUA_INT_LONG -#endif -#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT - -#elif defined(LUA_C89_NUMBERS) /* }{ */ -/* -** largest types available for C89 ('long' and 'double') -*/ -#define LUA_INT_TYPE LUA_INT_LONG -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE - -#endif /* } */ - - -/* -** default configuration for 64-bit Lua ('long long' and 'double') -*/ -#if !defined(LUA_INT_TYPE) -#define LUA_INT_TYPE LUA_INT_LONGLONG -#endif - -#if !defined(LUA_FLOAT_TYPE) -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE -#endif - -/* }================================================================== */ - - - - -/* -** {================================================================== -** Configuration for Paths. -** =================================================================== -*/ - -/* -** LUA_PATH_SEP is the character that separates templates in a path. -** LUA_PATH_MARK is the string that marks the substitution points in a -** template. -** LUA_EXEC_DIR in a Windows path is replaced by the executable's -** directory. -*/ -#define LUA_PATH_SEP ";" -#define LUA_PATH_MARK "?" -#define LUA_EXEC_DIR "!" - - -/* -@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for -** Lua libraries. -@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for -** C libraries. -** CHANGE them if your machine has a non-conventional directory -** hierarchy or if you want to install your libraries in -** non-conventional directories. -*/ -#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#if defined(_WIN32) /* { */ -/* -** In Windows, any exclamation mark ('!') in the path is replaced by the -** path of the directory of the executable file of the current process. -*/ -#define LUA_LDIR "!\\lua\\" -#define LUA_CDIR "!\\" -#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ - LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ - ".\\?.lua;" ".\\?\\init.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" \ - LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll" - -#else /* }{ */ - -#define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" -#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" -#define LUA_PATH_DEFAULT EDIZON_DIR "/editor/scripts/?.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" -#endif - - -/* -@@ LUA_DIRSEP is the directory separator (for submodules). -** CHANGE it if your machine does not use "/" as the directory separator -** and is not Windows. (On Windows Lua automatically uses "\".) -*/ -#if defined(_WIN32) -#define LUA_DIRSEP "\\" -#else -#define LUA_DIRSEP "/" -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Marks for exported symbols in the C code -** =================================================================== -*/ - -/* -@@ LUA_API is a mark for all core API functions. -@@ LUALIB_API is a mark for all auxiliary library functions. -@@ LUAMOD_API is a mark for all standard library opening functions. -** CHANGE them if you need to define those functions in some special way. -** For instance, if you want to create one Windows DLL with the core and -** the libraries, you may want to use the following definition (define -** LUA_BUILD_AS_DLL to get it). -*/ -#if defined(LUA_BUILD_AS_DLL) /* { */ - -#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ -#define LUA_API __declspec(dllexport) -#else /* }{ */ -#define LUA_API __declspec(dllimport) -#endif /* } */ - -#else /* }{ */ - -#define LUA_API extern - -#endif /* } */ - - -/* more often than not the libs go together with the core */ -#define LUALIB_API LUA_API -#define LUAMOD_API LUALIB_API - - -/* -@@ LUAI_FUNC is a mark for all extern functions that are not to be -** exported to outside modules. -@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables -** that are not to be exported to outside modules (LUAI_DDEF for -** definitions and LUAI_DDEC for declarations). -** CHANGE them if you need to mark them in some special way. Elf/gcc -** (versions 3.2 and later) mark them as "hidden" to optimize access -** when Lua is compiled as a shared library. Not all elf targets support -** this attribute. Unfortunately, gcc does not offer a way to check -** whether the target offers that support, and those without support -** give a warning about it. To avoid these warnings, change to the -** default definition. -*/ -#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) /* { */ -#define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#else /* }{ */ -#define LUAI_FUNC extern -#endif /* } */ - -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Compatibility with previous versions -** =================================================================== -*/ - -/* -@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. -@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. -** You can define it to get all options, or change specific options -** to fit your specific needs. -*/ -#if defined(LUA_COMPAT_5_2) /* { */ - -/* -@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated -** functions in the mathematical library. -*/ -#define LUA_COMPAT_MATHLIB - -/* -@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. -*/ -#define LUA_COMPAT_BITLIB - -/* -@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. -*/ -#define LUA_COMPAT_IPAIRS - -/* -@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for -** manipulating other integer types (lua_pushunsigned, lua_tounsigned, -** luaL_checkint, luaL_checklong, etc.) -*/ -#define LUA_COMPAT_APIINTCASTS - -#endif /* } */ - - -#if defined(LUA_COMPAT_5_1) /* { */ - -/* Incompatibilities from 5.2 -> 5.3 */ -#define LUA_COMPAT_MATHLIB -#define LUA_COMPAT_APIINTCASTS - -/* -@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. -** You can replace it with 'table.unpack'. -*/ -#define LUA_COMPAT_UNPACK - -/* -@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. -** You can replace it with 'package.searchers'. -*/ -#define LUA_COMPAT_LOADERS - -/* -@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. -** You can call your C function directly (with light C functions). -*/ -#define lua_cpcall(L,f,u) \ - (lua_pushcfunction(L, (f)), \ - lua_pushlightuserdata(L,(u)), \ - lua_pcall(L,1,0,0)) - - -/* -@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. -** You can rewrite 'log10(x)' as 'log(x, 10)'. -*/ -#define LUA_COMPAT_LOG10 - -/* -@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base -** library. You can rewrite 'loadstring(s)' as 'load(s)'. -*/ -#define LUA_COMPAT_LOADSTRING - -/* -@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. -*/ -#define LUA_COMPAT_MAXN - -/* -@@ The following macros supply trivial compatibility for some -** changes in the API. The macros themselves document how to -** change your code to avoid using them. -*/ -#define lua_strlen(L,i) lua_rawlen(L, (i)) - -#define lua_objlen(L,i) lua_rawlen(L, (i)) - -#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) -#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) - -/* -@@ LUA_COMPAT_MODULE controls compatibility with previous -** module functions 'module' (Lua) and 'luaL_register' (C). -*/ -#define LUA_COMPAT_MODULE - -#endif /* } */ - - -/* -@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a -@@ a float mark ('.0'). -** This macro is not on by default even in compatibility mode, -** because this is not really an incompatibility. -*/ -/* #define LUA_COMPAT_FLOATSTRING */ - -/* }================================================================== */ - - - -/* -** {================================================================== -** Configuration for Numbers. -** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* -** satisfy your needs. -** =================================================================== -*/ - -/* -@@ LUA_NUMBER is the floating-point type used by Lua. -@@ LUAI_UACNUMBER is the result of a 'default argument promotion' -@@ over a floating number. -@@ l_mathlim(x) corrects limit name 'x' to the proper float type -** by prefixing it with one of FLT/DBL/LDBL. -@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. -@@ LUA_NUMBER_FMT is the format for writing floats. -@@ lua_number2str converts a float to a string. -@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. -@@ l_floor takes the floor of a float. -@@ lua_str2number converts a decimal numeric string to a number. -*/ - - -/* The following definitions are good for most cases here */ - -#define l_floor(x) (l_mathop(floor)(x)) - -#define lua_number2str(s,sz,n) \ - l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) - -/* -@@ lua_numbertointeger converts a float number to an integer, or -** returns 0 if float is not within the range of a lua_Integer. -** (The range comparisons are tricky because of rounding. The tests -** here assume a two-complement representation, where MININTEGER always -** has an exact representation as a float; MAXINTEGER may not have one, -** and therefore its conversion to float may have an ill-defined value.) -*/ -#define lua_numbertointeger(n,p) \ - ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ - (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ - (*(p) = (LUA_INTEGER)(n), 1)) - - -/* now the variable definitions */ - -#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ - -#define LUA_NUMBER float - -#define l_mathlim(n) (FLT_##n) - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.7g" - -#define l_mathop(op) op##f - -#define lua_str2number(s,p) strtof((s), (p)) - - -#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ - -#define LUA_NUMBER long double - -#define l_mathlim(n) (LDBL_##n) - -#define LUAI_UACNUMBER long double - -#define LUA_NUMBER_FRMLEN "L" -#define LUA_NUMBER_FMT "%.19Lg" - -#define l_mathop(op) op##l - -#define lua_str2number(s,p) strtold((s), (p)) - -#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ - -#define LUA_NUMBER double - -#define l_mathlim(n) (DBL_##n) - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.14g" - -#define l_mathop(op) op - -#define lua_str2number(s,p) strtod((s), (p)) - -#else /* }{ */ - -#error "numeric float type not defined" - -#endif /* } */ - - - -/* -@@ LUA_INTEGER is the integer type used by Lua. -** -@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. -** -@@ LUAI_UACINT is the result of a 'default argument promotion' -@@ over a lUA_INTEGER. -@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. -@@ LUA_INTEGER_FMT is the format for writing integers. -@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. -@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. -@@ lua_integer2str converts an integer to a string. -*/ - - -/* The following definitions are good for most cases here */ - -#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" - -#define LUAI_UACINT LUA_INTEGER - -#define lua_integer2str(s,sz,n) \ - l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) - -/* -** use LUAI_UACINT here to avoid problems with promotions (which -** can turn a comparison between unsigneds into a signed comparison) -*/ -#define LUA_UNSIGNED unsigned LUAI_UACINT - - -/* now the variable definitions */ - -#if LUA_INT_TYPE == LUA_INT_INT /* { int */ - -#define LUA_INTEGER int -#define LUA_INTEGER_FRMLEN "" - -#define LUA_MAXINTEGER INT_MAX -#define LUA_MININTEGER INT_MIN - -#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ - -#define LUA_INTEGER long -#define LUA_INTEGER_FRMLEN "l" - -#define LUA_MAXINTEGER LONG_MAX -#define LUA_MININTEGER LONG_MIN - -#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ - -/* use presence of macro LLONG_MAX as proxy for C99 compliance */ -#if defined(LLONG_MAX) /* { */ -/* use ISO C99 stuff */ - -#define LUA_INTEGER long long -#define LUA_INTEGER_FRMLEN "ll" - -#define LUA_MAXINTEGER LLONG_MAX -#define LUA_MININTEGER LLONG_MIN - -#elif defined(LUA_USE_WINDOWS) /* }{ */ -/* in Windows, can use specific Windows types */ - -#define LUA_INTEGER __int64 -#define LUA_INTEGER_FRMLEN "I64" - -#define LUA_MAXINTEGER _I64_MAX -#define LUA_MININTEGER _I64_MIN - -#else /* }{ */ - -#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ - or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" - -#endif /* } */ - -#else /* }{ */ - -#error "numeric integer type not defined" - -#endif /* } */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Dependencies with C99 and other C details -** =================================================================== -*/ - -/* -@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. -** (All uses in Lua have only one format item.) -*/ -#if !defined(LUA_USE_C89) -#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) -#else -#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) -#endif - - -/* -@@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' does that conversion. Otherwise, you can -** leave 'lua_strx2number' undefined and Lua will provide its own -** implementation. -*/ -#if !defined(LUA_USE_C89) -#define lua_strx2number(s,p) lua_str2number(s,p) -#endif - - -/* -@@ lua_pointer2str converts a pointer to a readable string in a -** non-specified way. -*/ -#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) - - -/* -@@ lua_number2strx converts a float to an hexadecimal numeric string. -** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. -** Otherwise, you can leave 'lua_number2strx' undefined and Lua will -** provide its own implementation. -*/ -#if !defined(LUA_USE_C89) -#define lua_number2strx(L,b,sz,f,n) \ - ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) -#endif - - -/* -** 'strtof' and 'opf' variants for math functions are not valid in -** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the -** availability of these variants. ('math.h' is already included in -** all files that use these macros.) -*/ -#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) -#undef l_mathop /* variants not available */ -#undef lua_str2number -#define l_mathop(op) (lua_Number)op /* no variant */ -#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) -#endif - - -/* -@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation -** functions. It must be a numerical type; Lua will use 'intptr_t' if -** available, otherwise it will use 'ptrdiff_t' (the nearest thing to -** 'intptr_t' in C89) -*/ -#define LUA_KCONTEXT ptrdiff_t - -#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ - __STDC_VERSION__ >= 199901L -#include -#if defined(INTPTR_MAX) /* even in C99 this type is optional */ -#undef LUA_KCONTEXT -#define LUA_KCONTEXT intptr_t -#endif -#endif - - -/* -@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). -** Change that if you do not want to use C locales. (Code using this -** macro must include header 'locale.h'.) -*/ -#if !defined(lua_getlocaledecpoint) -#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Language Variations -** ===================================================================== -*/ - -/* -@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some -** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from -** numbers to strings. Define LUA_NOCVTS2N to turn off automatic -** coercion from strings to numbers. -*/ -/* #define LUA_NOCVTN2S */ -/* #define LUA_NOCVTS2N */ - - -/* -@@ LUA_USE_APICHECK turns on several consistency checks on the C API. -** Define it as a help when debugging C code. -*/ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(l,e) assert(e) -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Macros that affect the API and must be stable (that is, must be the -** same when you compile Lua and when you compile code that links to -** Lua). You probably do not want/need to change them. -** ===================================================================== -*/ - -/* -@@ LUAI_MAXSTACK limits the size of the Lua stack. -** CHANGE it if you need a different limit. This limit is arbitrary; -** its only purpose is to stop Lua from consuming unlimited stack -** space (and to reserve some numbers for pseudo-indices). -*/ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif - - -/* -@@ LUA_EXTRASPACE defines the size of a raw memory area associated with -** a Lua state with very fast access. -** CHANGE it if you need a different size. -*/ -#define LUA_EXTRASPACE (sizeof(void *)) - - -/* -@@ LUA_IDSIZE gives the maximum size for the description of the source -@@ of a function in debug information. -** CHANGE it if you want a different size. -*/ -#define LUA_IDSIZE 60 - - -/* -@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. -** CHANGE it if it uses too much C-stack space. (For long double, -** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a -** smaller buffer would force a memory allocation for each call to -** 'string.format'.) -*/ -#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE -#define LUAL_BUFFERSIZE 8192 -#else -#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) -#endif - -/* }================================================================== */ - - -/* -@@ LUA_QL describes how error messages quote program elements. -** Lua does not use these macros anymore; they are here for -** compatibility only. -*/ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - - - - -/* =================================================================== */ - -/* -** Local configuration. You can use this space to add your redefinitions -** without modifying the main part of the file. -*/ - - - - - -#endif +/* +** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef luaconf_h +#define luaconf_h + +#include +#include +#include + + +/* +** =================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance compiling it with 32-bit numbers or +** restricting it to C89. +** ===================================================================== +*/ + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You +** can also define LUA_32BITS in the make file, but changing here you +** ensure that all software connected to Lua will be compiled with the +** same configuration. +*/ +/* #define LUA_32BITS */ + + +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ + + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ +#endif + + +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#endif + + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#endif + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS +#endif + + + +/* +@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. +*/ +/* avoid undefined shifts */ +#if ((INT_MAX >> 15) >> 15) >= 1 +#define LUAI_BITSINT 32 +#else +/* 'int' always must have at least 16 bits */ +#define LUAI_BITSINT 16 +#endif + + +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options (if supported +** by your C compiler). The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** compliant with C99, which may not have support for 'long long'). +*/ + +/* predefined options for LUA_INT_TYPE */ +#define LUA_INT_INT 1 +#define LUA_INT_LONG 2 +#define LUA_INT_LONGLONG 3 + +/* predefined options for LUA_FLOAT_TYPE */ +#define LUA_FLOAT_FLOAT 1 +#define LUA_FLOAT_DOUBLE 2 +#define LUA_FLOAT_LONGDOUBLE 3 + +#if defined(LUA_32BITS) /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif defined(LUA_C89_NUMBERS) /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#endif /* } */ + + +/* +** default configuration for 64-bit Lua ('long long' and 'double') +*/ +#if !defined(LUA_INT_TYPE) +#define LUA_INT_TYPE LUA_INT_LONGLONG +#endif + +#if !defined(LUA_FLOAT_TYPE) +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE +#endif + +/* }================================================================== */ + + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +*/ +#define LUA_PATH_SEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXEC_DIR "!" + + +/* +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +** Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +** C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#if defined(_WIN32) /* { */ +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" + +#else /* }{ */ + +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" +#define LUA_PATH_DEFAULT EDIZON_DIR "/editor/scripts/?.lua" +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== +*/ + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) /* { */ + +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API +#define LUAMOD_API LUALIB_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables +** that are not to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. +@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_2) /* { */ + +/* +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. +*/ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. +*/ +#define LUA_COMPAT_BITLIB + +/* +@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. +*/ +#define LUA_COMPAT_IPAIRS + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +*/ +#define LUA_COMPAT_APIINTCASTS + +#endif /* } */ + + +#if defined(LUA_COMPAT_5_1) /* { */ + +/* Incompatibilities from 5.2 -> 5.3 */ +#define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_APIINTCASTS + +/* +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. +*/ +#define LUA_COMPAT_UNPACK + +/* +@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. +** You can replace it with 'package.searchers'. +*/ +#define LUA_COMPAT_LOADERS + +/* +@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. +** You can call your C function directly (with light C functions). +*/ +#define lua_cpcall(L,f,u) \ + (lua_pushcfunction(L, (f)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) + + +/* +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. +*/ +#define LUA_COMPAT_LOG10 + +/* +@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base +** library. You can rewrite 'loadstring(s)' as 'load(s)'. +*/ +#define LUA_COMPAT_LOADSTRING + +/* +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. +*/ +#define LUA_COMPAT_MAXN + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +/* +@@ LUA_COMPAT_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). +*/ +#define LUA_COMPAT_MODULE + +#endif /* } */ + + +/* +@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a +@@ a float mark ('.0'). +** This macro is not on by default even in compatibility mode, +** because this is not really an incompatibility. +*/ +/* #define LUA_COMPAT_FLOATSTRING */ + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Numbers. +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUA_NUMBER is the floating-point type used by Lua. +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' +@@ over a floating number. +@@ l_mathlim(x) corrects limit name 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeric string to a number. +*/ + + +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) \ + l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n)) + +/* +@@ lua_numbertointeger converts a float number to an integer, or +** returns 0 if float is not within the range of a lua_Integer. +** (The range comparisons are tricky because of rounding. The tests +** here assume a two-complement representation, where MININTEGER always +** has an exact representation as a float; MAXINTEGER may not have one, +** and therefore its conversion to float may have an ill-defined value.) +*/ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_mathlim(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_mathlim(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_mathlim(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + + + +/* +@@ LUA_INTEGER is the integer type used by Lua. +** +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +** +@@ LUAI_UACINT is the result of a 'default argument promotion' +@@ over a lUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ lua_integer2str converts an integer to a string. +*/ + + +/* The following definitions are good for most cases here */ + +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" + +#define LUAI_UACINT LUA_INTEGER + +#define lua_integer2str(s,sz,n) \ + l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n)) + +/* +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) +*/ +#define LUA_UNSIGNED unsigned LUAI_UACINT + + +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Dependencies with C99 and other C details +** =================================================================== +*/ + +/* +@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. +** (All uses in Lua have only one format item.) +*/ +#if !defined(LUA_USE_C89) +#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) +#else +#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) +#endif + + +/* +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif + + +/* +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to an hexadecimal numeric string. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. +*/ +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) +#endif + + +/* +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) +*/ +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) +#endif + + +/* +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) +*/ +#define LUA_KCONTEXT ptrdiff_t + +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t +#endif +#endif + + +/* +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include header 'locale.h'.) +*/ +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Language Variations +** ===================================================================== +*/ + +/* +@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some +** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from +** numbers to strings. Define LUA_NOCVTS2N to turn off automatic +** coercion from strings to numbers. +*/ +/* #define LUA_NOCVTN2S */ +/* #define LUA_NOCVTS2N */ + + +/* +@@ LUA_USE_APICHECK turns on several consistency checks on the C API. +** Define it as a help when debugging C code. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(l,e) assert(e) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). You probably do not want/need to change them. +** ===================================================================== +*/ + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + + +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@@ of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. (For long double, +** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a +** smaller buffer would force a memory allocation for each call to +** 'string.format'.) +*/ +#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE +#define LUAL_BUFFERSIZE 8192 +#else +#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) +#endif + +/* }================================================================== */ + + +/* +@@ LUA_QL describes how error messages quote program elements. +** Lua does not use these macros anymore; they are here for +** compatibility only. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + + + +#endif diff --git a/libs/lua/include/lualib.h b/libs/lua/include/lualib.h index f5304aa0..cb96f768 100644 --- a/libs/lua/include/lualib.h +++ b/libs/lua/include/lualib.h @@ -1,61 +1,61 @@ -/* -** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lualib_h -#define lualib_h - -#include "lua.h" - - -/* version suffix for environment variable names */ -#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR - - -LUAMOD_API int (luaopen_base) (lua_State *L); - -#define LUA_COLIBNAME "coroutine" -LUAMOD_API int (luaopen_coroutine) (lua_State *L); - -#define LUA_TABLIBNAME "table" -LUAMOD_API int (luaopen_table) (lua_State *L); - -#define LUA_IOLIBNAME "io" -LUAMOD_API int (luaopen_io) (lua_State *L); - -#define LUA_OSLIBNAME "os" -LUAMOD_API int (luaopen_os) (lua_State *L); - -#define LUA_STRLIBNAME "string" -LUAMOD_API int (luaopen_string) (lua_State *L); - -#define LUA_UTF8LIBNAME "utf8" -LUAMOD_API int (luaopen_utf8) (lua_State *L); - -#define LUA_BITLIBNAME "bit32" -LUAMOD_API int (luaopen_bit32) (lua_State *L); - -#define LUA_MATHLIBNAME "math" -LUAMOD_API int (luaopen_math) (lua_State *L); - -#define LUA_DBLIBNAME "debug" -LUAMOD_API int (luaopen_debug) (lua_State *L); - -#define LUA_LOADLIBNAME "package" -LUAMOD_API int (luaopen_package) (lua_State *L); - - -/* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); - - - -#if !defined(lua_assert) -#define lua_assert(x) ((void)0) -#endif - - -#endif +/* +** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +/* version suffix for environment variable names */ +#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + + +LUAMOD_API int (luaopen_base) (lua_State *L); + +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + +#define LUA_TABLIBNAME "table" +LUAMOD_API int (luaopen_table) (lua_State *L); + +#define LUA_IOLIBNAME "io" +LUAMOD_API int (luaopen_io) (lua_State *L); + +#define LUA_OSLIBNAME "os" +LUAMOD_API int (luaopen_os) (lua_State *L); + +#define LUA_STRLIBNAME "string" +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + +#define LUA_BITLIBNAME "bit32" +LUAMOD_API int (luaopen_bit32) (lua_State *L); + +#define LUA_MATHLIBNAME "math" +LUAMOD_API int (luaopen_math) (lua_State *L); + +#define LUA_DBLIBNAME "debug" +LUAMOD_API int (luaopen_debug) (lua_State *L); + +#define LUA_LOADLIBNAME "package" +LUAMOD_API int (luaopen_package) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (luaL_openlibs) (lua_State *L); + + + +#if !defined(lua_assert) +#define lua_assert(x) ((void)0) +#endif + + +#endif diff --git a/libs/lua/include/lundump.h b/libs/lua/include/lundump.h index ce492d68..e89ae06f 100644 --- a/libs/lua/include/lundump.h +++ b/libs/lua/include/lundump.h @@ -1,32 +1,32 @@ -/* -** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#ifndef lundump_h -#define lundump_h - -#include "llimits.h" -#include "lobject.h" -#include "lzio.h" - - -/* data to catch conversion errors */ -#define LUAC_DATA "\x19\x93\r\n\x1a\n" - -#define LUAC_INT 0x5678 -#define LUAC_NUM cast_num(370.5) - -#define MYINT(s) (s[0]-'0') -#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) -#define LUAC_FORMAT 0 /* this is the official format */ - -/* load one chunk; from lundump.c */ -LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); - -/* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, - void* data, int strip); - -#endif +/* +** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#ifndef lundump_h +#define lundump_h + +#include "llimits.h" +#include "lobject.h" +#include "lzio.h" + + +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" + +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) + +#define MYINT(s) (s[0]-'0') +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_FORMAT 0 /* this is the official format */ + +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); + +#endif diff --git a/libs/lua/include/lvm.h b/libs/lua/include/lvm.h index a8f954f0..40d1eb8a 100644 --- a/libs/lua/include/lvm.h +++ b/libs/lua/include/lvm.h @@ -1,113 +1,113 @@ -/* -** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#ifndef lvm_h -#define lvm_h - - -#include "ldo.h" -#include "lobject.h" -#include "ltm.h" - - -#if !defined(LUA_NOCVTN2S) -#define cvt2str(o) ttisnumber(o) -#else -#define cvt2str(o) 0 /* no conversion from numbers to strings */ -#endif - - -#if !defined(LUA_NOCVTS2N) -#define cvt2num(o) ttisstring(o) -#else -#define cvt2num(o) 0 /* no conversion from strings to numbers */ -#endif - - -/* -** You can define LUA_FLOORN2I if you want to convert floats to integers -** by flooring them (instead of raising an error if they are not -** integral values) -*/ -#if !defined(LUA_FLOORN2I) -#define LUA_FLOORN2I 0 -#endif - - -#define tonumber(o,n) \ - (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) - -#define tointeger(o,i) \ - (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) - -#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) - -#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) - - -/* -** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, -** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, -** return 0 (meaning it will have to check metamethod) with 'slot' -** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). -** 'f' is the raw get function to use. -*/ -#define luaV_fastget(L,t,k,slot,f) \ - (!ttistable(t) \ - ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ - : (slot = f(hvalue(t), k), /* else, do raw access */ \ - !ttisnil(slot))) /* result not nil? */ - -/* -** standard implementation for 'gettable' -*/ -#define luaV_gettable(L,t,k,v) { const TValue *slot; \ - if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ - else luaV_finishget(L,t,k,v,slot); } - - -/* -** Fast track for set table. If 't' is a table and 't[k]' is not nil, -** call GC barrier, do a raw 't[k]=v', and return true; otherwise, -** return false with 'slot' equal to NULL (if 't' is not a table) or -** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro -** returns true, there is no need to 'invalidateTMcache', because the -** call is not creating a new entry. -*/ -#define luaV_fastset(L,t,k,slot,f,v) \ - (!ttistable(t) \ - ? (slot = NULL, 0) \ - : (slot = f(hvalue(t), k), \ - ttisnil(slot) ? 0 \ - : (luaC_barrierback(L, hvalue(t), v), \ - setobj2t(L, cast(TValue *,slot), v), \ - 1))) - - -#define luaV_settable(L,t,k,v) { const TValue *slot; \ - if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ - luaV_finishset(L,t,k,v,slot); } - - - -LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); -LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); -LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); -LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot); -LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot); -LUAI_FUNC void luaV_finishOp (lua_State *L); -LUAI_FUNC void luaV_execute (lua_State *L); -LUAI_FUNC void luaV_concat (lua_State *L, int total); -LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); -LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); -LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); - -#endif +/* +** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" +#include "ltm.h" + + +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#endif + + +/* +** You can define LUA_FLOORN2I if you want to convert floats to integers +** by flooring them (instead of raising an error if they are not +** integral values) +*/ +#if !defined(LUA_FLOORN2I) +#define LUA_FLOORN2I 0 +#endif + + +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) + +#define tointeger(o,i) \ + (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) + +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) + +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, +** return 0 (meaning it will have to check metamethod) with 'slot' +** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). +** 'f' is the raw get function to use. +*/ +#define luaV_fastget(L,t,k,slot,f) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(slot))) /* result not nil? */ + +/* +** standard implementation for 'gettable' +*/ +#define luaV_gettable(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else luaV_finishget(L,t,k,v,slot); } + + +/* +** Fast track for set table. If 't' is a table and 't[k]' is not nil, +** call GC barrier, do a raw 't[k]=v', and return true; otherwise, +** return false with 'slot' equal to NULL (if 't' is not a table) or +** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro +** returns true, there is no need to 'invalidateTMcache', because the +** call is not creating a new entry. +*/ +#define luaV_fastset(L,t,k,slot,f,v) \ + (!ttistable(t) \ + ? (slot = NULL, 0) \ + : (slot = f(hvalue(t), k), \ + ttisnil(slot) ? 0 \ + : (luaC_barrierback(L, hvalue(t), v), \ + setobj2t(L, cast(TValue *,slot), v), \ + 1))) + + +#define luaV_settable(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + luaV_finishset(L,t,k,v,slot); } + + + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); + +#endif diff --git a/libs/lua/include/lzio.h b/libs/lua/include/lzio.h index d8978708..17f3a6bf 100644 --- a/libs/lua/include/lzio.h +++ b/libs/lua/include/lzio.h @@ -1,66 +1,66 @@ -/* -** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $ -** Buffered streams -** See Copyright Notice in lua.h -*/ - - -#ifndef lzio_h -#define lzio_h - -#include "lua.h" - -#include "lmem.h" - - -#define EOZ (-1) /* end of stream */ - -typedef struct Zio ZIO; - -#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) - - -typedef struct Mbuffer { - char *buffer; - size_t n; - size_t buffsize; -} Mbuffer; - -#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) - -#define luaZ_buffer(buff) ((buff)->buffer) -#define luaZ_sizebuffer(buff) ((buff)->buffsize) -#define luaZ_bufflen(buff) ((buff)->n) - -#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) -#define luaZ_resetbuffer(buff) ((buff)->n = 0) - - -#define luaZ_resizebuffer(L, buff, size) \ - ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ - (buff)->buffsize, size), \ - (buff)->buffsize = size) - -#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) - - -LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, - void *data); -LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ - - - -/* --------- Private Part ------------------ */ - -struct Zio { - size_t n; /* bytes still unread */ - const char *p; /* current position in buffer */ - lua_Reader reader; /* reader function */ - void *data; /* additional data */ - lua_State *L; /* Lua state (for reader) */ -}; - - -LUAI_FUNC int luaZ_fill (ZIO *z); - -#endif +/* +** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + +#include "lmem.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) + + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + + +#define luaZ_resizebuffer(L, buff, size) \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; /* reader function */ + void *data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int luaZ_fill (ZIO *z); + +#endif diff --git a/libs/lua/source/lapi.c b/libs/lua/source/lapi.c index 02b7fab7..a8803327 100644 --- a/libs/lua/source/lapi.c +++ b/libs/lua/source/lapi.c @@ -1,1299 +1,1299 @@ -/* -** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $ -** Lua API -** See Copyright Notice in lua.h -*/ - -#define lapi_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" - - - -const char lua_ident[] = - "$LuaVersion: " LUA_COPYRIGHT " $" - "$LuaAuthors: " LUA_AUTHORS " $"; - - -/* value at a non-valid index */ -#define NONVALIDVALUE cast(TValue *, luaO_nilobject) - -/* corresponding test */ -#define isvalid(o) ((o) != luaO_nilobject) - -/* test for pseudo index */ -#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) - -/* test for upvalue */ -#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) - -/* test for valid but not pseudo index */ -#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) - -#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index") - -#define api_checkstackindex(l, i, o) \ - api_check(l, isstackindex(i, o), "index not in the stack") - - -static TValue *index2addr (lua_State *L, int idx) { - CallInfo *ci = L->ci; - if (idx > 0) { - TValue *o = ci->func + idx; - api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); - if (o >= L->top) return NONVALIDVALUE; - else return o; - } - else if (!ispseudo(idx)) { /* negative index */ - api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); - return L->top + idx; - } - else if (idx == LUA_REGISTRYINDEX) - return &G(L)->l_registry; - else { /* upvalues */ - idx = LUA_REGISTRYINDEX - idx; - api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(ci->func)) /* light C function? */ - return NONVALIDVALUE; /* it has no upvalues */ - else { - CClosure *func = clCvalue(ci->func); - return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; - } - } -} - - -/* -** to be called by 'lua_checkstack' in protected mode, to grow stack -** capturing memory errors -*/ -static void growstack (lua_State *L, void *ud) { - int size = *(int *)ud; - luaD_growstack(L, size); -} - - -LUA_API int lua_checkstack (lua_State *L, int n) { - int res; - CallInfo *ci = L->ci; - lua_lock(L); - api_check(L, n >= 0, "negative 'n'"); - if (L->stack_last - L->top > n) /* stack large enough? */ - res = 1; /* yes; check is OK */ - else { /* no; need to grow stack */ - int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; - if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ - res = 0; /* no */ - else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); - } - if (res && ci->top < L->top + n) - ci->top = L->top + n; /* adjust frame top */ - lua_unlock(L); - return res; -} - - -LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { - int i; - if (from == to) return; - lua_lock(to); - api_checknelems(from, n); - api_check(from, G(from) == G(to), "moving among independent states"); - api_check(from, to->ci->top - to->top >= n, "stack overflow"); - from->top -= n; - for (i = 0; i < n; i++) { - setobj2s(to, to->top, from->top + i); - to->top++; /* stack already checked by previous 'api_check' */ - } - lua_unlock(to); -} - - -LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { - lua_CFunction old; - lua_lock(L); - old = G(L)->panic; - G(L)->panic = panicf; - lua_unlock(L); - return old; -} - - -LUA_API const lua_Number *lua_version (lua_State *L) { - static const lua_Number version = LUA_VERSION_NUM; - if (L == NULL) return &version; - else return G(L)->version; -} - - - -/* -** basic stack manipulation -*/ - - -/* -** convert an acceptable stack index into an absolute index -*/ -LUA_API int lua_absindex (lua_State *L, int idx) { - return (idx > 0 || ispseudo(idx)) - ? idx - : cast_int(L->top - L->ci->func) + idx; -} - - -LUA_API int lua_gettop (lua_State *L) { - return cast_int(L->top - (L->ci->func + 1)); -} - - -LUA_API void lua_settop (lua_State *L, int idx) { - StkId func = L->ci->func; - lua_lock(L); - if (idx >= 0) { - api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); - while (L->top < (func + 1) + idx) - setnilvalue(L->top++); - L->top = (func + 1) + idx; - } - else { - api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); - L->top += idx+1; /* 'subtract' index (index is negative) */ - } - lua_unlock(L); -} - - -/* -** Reverse the stack segment from 'from' to 'to' -** (auxiliary to 'lua_rotate') -*/ -static void reverse (lua_State *L, StkId from, StkId to) { - for (; from < to; from++, to--) { - TValue temp; - setobj(L, &temp, from); - setobjs2s(L, from, to); - setobj2s(L, to, &temp); - } -} - - -/* -** Let x = AB, where A is a prefix of length 'n'. Then, -** rotate x n == BA. But BA == (A^r . B^r)^r. -*/ -LUA_API void lua_rotate (lua_State *L, int idx, int n) { - StkId p, t, m; - lua_lock(L); - t = L->top - 1; /* end of stack segment being rotated */ - p = index2addr(L, idx); /* start of segment */ - api_checkstackindex(L, idx, p); - api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); - m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ - reverse(L, p, m); /* reverse the prefix with length 'n' */ - reverse(L, m + 1, t); /* reverse the suffix */ - reverse(L, p, t); /* reverse the entire segment */ - lua_unlock(L); -} - - -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { - TValue *fr, *to; - lua_lock(L); - fr = index2addr(L, fromidx); - to = index2addr(L, toidx); - api_checkvalidindex(L, to); - setobj(L, to, fr); - if (isupvalue(toidx)) /* function upvalue? */ - luaC_barrier(L, clCvalue(L->ci->func), fr); - /* LUA_REGISTRYINDEX does not need gc barrier - (collector revisits it before finishing collection) */ - lua_unlock(L); -} - - -LUA_API void lua_pushvalue (lua_State *L, int idx) { - lua_lock(L); - setobj2s(L, L->top, index2addr(L, idx)); - api_incr_top(L); - lua_unlock(L); -} - - - -/* -** access functions (stack -> C) -*/ - - -LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (isvalid(o) ? ttnov(o) : LUA_TNONE); -} - - -LUA_API const char *lua_typename (lua_State *L, int t) { - UNUSED(L); - api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); - return ttypename(t); -} - - -LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (ttislcf(o) || (ttisCclosure(o))); -} - - -LUA_API int lua_isinteger (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return ttisinteger(o); -} - - -LUA_API int lua_isnumber (lua_State *L, int idx) { - lua_Number n; - const TValue *o = index2addr(L, idx); - return tonumber(o, &n); -} - - -LUA_API int lua_isstring (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisstring(o) || cvt2str(o)); -} - - -LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return (ttisfulluserdata(o) || ttislightuserdata(o)); -} - - -LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2addr(L, index1); - StkId o2 = index2addr(L, index2); - return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; -} - - -LUA_API void lua_arith (lua_State *L, int op) { - lua_lock(L); - if (op != LUA_OPUNM && op != LUA_OPBNOT) - api_checknelems(L, 2); /* all other operations expect two operands */ - else { /* for unary operations, add fake 2nd operand */ - api_checknelems(L, 1); - setobjs2s(L, L->top, L->top - 1); - api_incr_top(L); - } - /* first operand at top - 2, second at top - 1; result go to top - 2 */ - luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); - L->top--; /* remove second operand */ - lua_unlock(L); -} - - -LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { - StkId o1, o2; - int i = 0; - lua_lock(L); /* may call tag method */ - o1 = index2addr(L, index1); - o2 = index2addr(L, index2); - if (isvalid(o1) && isvalid(o2)) { - switch (op) { - case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; - case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; - case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; - default: api_check(L, 0, "invalid option"); - } - } - lua_unlock(L); - return i; -} - - -LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { - size_t sz = luaO_str2num(s, L->top); - if (sz != 0) - api_incr_top(L); - return sz; -} - - -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { - lua_Number n; - const TValue *o = index2addr(L, idx); - int isnum = tonumber(o, &n); - if (!isnum) - n = 0; /* call to 'tonumber' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return n; -} - - -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { - lua_Integer res; - const TValue *o = index2addr(L, idx); - int isnum = tointeger(o, &res); - if (!isnum) - res = 0; /* call to 'tointeger' may change 'n' even if it fails */ - if (pisnum) *pisnum = isnum; - return res; -} - - -LUA_API int lua_toboolean (lua_State *L, int idx) { - const TValue *o = index2addr(L, idx); - return !l_isfalse(o); -} - - -LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { - StkId o = index2addr(L, idx); - if (!ttisstring(o)) { - if (!cvt2str(o)) { /* not convertible? */ - if (len != NULL) *len = 0; - return NULL; - } - lua_lock(L); /* 'luaO_tostring' may create a new string */ - luaO_tostring(L, o); - luaC_checkGC(L); - o = index2addr(L, idx); /* previous call may reallocate the stack */ - lua_unlock(L); - } - if (len != NULL) - *len = vslen(o); - return svalue(o); -} - - -LUA_API size_t lua_rawlen (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttype(o)) { - case LUA_TSHRSTR: return tsvalue(o)->shrlen; - case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; - case LUA_TUSERDATA: return uvalue(o)->len; - case LUA_TTABLE: return luaH_getn(hvalue(o)); - default: return 0; - } -} - - -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - if (ttislcf(o)) return fvalue(o); - else if (ttisCclosure(o)) - return clCvalue(o)->f; - else return NULL; /* not a C function */ -} - - -LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttnov(o)) { - case LUA_TUSERDATA: return getudatamem(uvalue(o)); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } -} - - -LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - return (!ttisthread(o)) ? NULL : thvalue(o); -} - - -LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = index2addr(L, idx); - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TLCL: return clLvalue(o); - case LUA_TCCL: return clCvalue(o); - case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: return getudatamem(uvalue(o)); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } -} - - - -/* -** push functions (C -> stack) -*/ - - -LUA_API void lua_pushnil (lua_State *L) { - lua_lock(L); - setnilvalue(L->top); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { - lua_lock(L); - setfltvalue(L->top, n); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { - lua_lock(L); - setivalue(L->top, n); - api_incr_top(L); - lua_unlock(L); -} - - -/* -** Pushes on the stack a string with given length. Avoid using 's' when -** 'len' == 0 (as 's' can be NULL in that case), due to later use of -** 'memcmp' and 'memcpy'. -*/ -LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { - TString *ts; - lua_lock(L); - ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); - setsvalue2s(L, L->top, ts); - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return getstr(ts); -} - - -LUA_API const char *lua_pushstring (lua_State *L, const char *s) { - lua_lock(L); - if (s == NULL) - setnilvalue(L->top); - else { - TString *ts; - ts = luaS_new(L, s); - setsvalue2s(L, L->top, ts); - s = getstr(ts); /* internal copy's address */ - } - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return s; -} - - -LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, - va_list argp) { - const char *ret; - lua_lock(L); - ret = luaO_pushvfstring(L, fmt, argp); - luaC_checkGC(L); - lua_unlock(L); - return ret; -} - - -LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { - const char *ret; - va_list argp; - lua_lock(L); - va_start(argp, fmt); - ret = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - luaC_checkGC(L); - lua_unlock(L); - return ret; -} - - -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - lua_lock(L); - if (n == 0) { - setfvalue(L->top, fn); - api_incr_top(L); - } - else { - CClosure *cl; - api_checknelems(L, n); - api_check(L, n <= MAXUPVAL, "upvalue index too large"); - cl = luaF_newCclosure(L, n); - cl->f = fn; - L->top -= n; - while (n--) { - setobj2n(L, &cl->upvalue[n], L->top + n); - /* does not need barrier because closure is white */ - } - setclCvalue(L, L->top, cl); - api_incr_top(L); - luaC_checkGC(L); - } - lua_unlock(L); -} - - -LUA_API void lua_pushboolean (lua_State *L, int b) { - lua_lock(L); - setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { - lua_lock(L); - setpvalue(L->top, p); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API int lua_pushthread (lua_State *L) { - lua_lock(L); - setthvalue(L, L->top, L); - api_incr_top(L); - lua_unlock(L); - return (G(L)->mainthread == L); -} - - - -/* -** get functions (Lua -> stack) -*/ - - -static int auxgetstr (lua_State *L, const TValue *t, const char *k) { - const TValue *slot; - TString *str = luaS_new(L, k); - if (luaV_fastget(L, t, str, slot, luaH_getstr)) { - setobj2s(L, L->top, slot); - api_incr_top(L); - } - else { - setsvalue2s(L, L->top, str); - api_incr_top(L); - luaV_finishget(L, t, L->top - 1, L->top - 1, slot); - } - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_getglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); - lua_lock(L); - return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); -} - - -LUA_API int lua_gettable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - luaV_gettable(L, t, L->top - 1, L->top - 1); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { - lua_lock(L); - return auxgetstr(L, index2addr(L, idx), k); -} - - -LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { - StkId t; - const TValue *slot; - lua_lock(L); - t = index2addr(L, idx); - if (luaV_fastget(L, t, n, slot, luaH_getint)) { - setobj2s(L, L->top, slot); - api_incr_top(L); - } - else { - setivalue(L->top, n); - api_incr_top(L); - luaV_finishget(L, t, L->top - 1, L->top - 1, slot); - } - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawget (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top, luaH_getint(hvalue(t), n)); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { - StkId t; - TValue k; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setpvalue(&k, cast(void *, p)); - setobj2s(L, L->top, luaH_get(hvalue(t), &k)); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { - Table *t; - lua_lock(L); - t = luaH_new(L); - sethvalue(L, L->top, t); - api_incr_top(L); - if (narray > 0 || nrec > 0) - luaH_resize(L, t, narray, nrec); - luaC_checkGC(L); - lua_unlock(L); -} - - -LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TValue *obj; - Table *mt; - int res = 0; - lua_lock(L); - obj = index2addr(L, objindex); - switch (ttnov(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->metatable; - break; - default: - mt = G(L)->mt[ttnov(obj)]; - break; - } - if (mt != NULL) { - sethvalue(L, L->top, mt); - api_incr_top(L); - res = 1; - } - lua_unlock(L); - return res; -} - - -LUA_API int lua_getuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - o = index2addr(L, idx); - api_check(L, ttisfulluserdata(o), "full userdata expected"); - getuservalue(L, uvalue(o), L->top); - api_incr_top(L); - lua_unlock(L); - return ttnov(L->top - 1); -} - - -/* -** set functions (stack -> Lua) -*/ - -/* -** t[k] = value at the top of the stack (where 'k' is a string) -*/ -static void auxsetstr (lua_State *L, const TValue *t, const char *k) { - const TValue *slot; - TString *str = luaS_new(L, k); - api_checknelems(L, 1); - if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) - L->top--; /* pop value */ - else { - setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ - api_incr_top(L); - luaV_finishset(L, t, L->top - 1, L->top - 2, slot); - L->top -= 2; /* pop value and key */ - } - lua_unlock(L); /* lock done by caller */ -} - - -LUA_API void lua_setglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); - lua_lock(L); /* unlock done in 'auxsetstr' */ - auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); -} - - -LUA_API void lua_settable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = index2addr(L, idx); - luaV_settable(L, t, L->top - 2, L->top - 1); - L->top -= 2; /* pop index and value */ - lua_unlock(L); -} - - -LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { - lua_lock(L); /* unlock done in 'auxsetstr' */ - auxsetstr(L, index2addr(L, idx), k); -} - - -LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { - StkId t; - const TValue *slot; - lua_lock(L); - api_checknelems(L, 1); - t = index2addr(L, idx); - if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) - L->top--; /* pop value */ - else { - setivalue(L->top, n); - api_incr_top(L); - luaV_finishset(L, t, L->top - 1, L->top - 2, slot); - L->top -= 2; /* pop value and key */ - } - lua_unlock(L); -} - - -LUA_API void lua_rawset (lua_State *L, int idx) { - StkId o; - TValue *slot; - lua_lock(L); - api_checknelems(L, 2); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - slot = luaH_set(L, hvalue(o), L->top - 2); - setobj2t(L, slot, L->top - 1); - invalidateTMcache(hvalue(o)); - luaC_barrierback(L, hvalue(o), L->top-1); - L->top -= 2; - lua_unlock(L); -} - - -LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - luaH_setint(L, hvalue(o), n, L->top - 1); - luaC_barrierback(L, hvalue(o), L->top-1); - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { - StkId o; - TValue k, *slot; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - setpvalue(&k, cast(void *, p)); - slot = luaH_set(L, hvalue(o), &k); - setobj2t(L, slot, L->top - 1); - luaC_barrierback(L, hvalue(o), L->top - 1); - L->top--; - lua_unlock(L); -} - - -LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TValue *obj; - Table *mt; - lua_lock(L); - api_checknelems(L, 1); - obj = index2addr(L, objindex); - if (ttisnil(L->top - 1)) - mt = NULL; - else { - api_check(L, ttistable(L->top - 1), "table expected"); - mt = hvalue(L->top - 1); - } - switch (ttnov(obj)) { - case LUA_TTABLE: { - hvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, gcvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - case LUA_TUSERDATA: { - uvalue(obj)->metatable = mt; - if (mt) { - luaC_objbarrier(L, uvalue(obj), mt); - luaC_checkfinalizer(L, gcvalue(obj), mt); - } - break; - } - default: { - G(L)->mt[ttnov(obj)] = mt; - break; - } - } - L->top--; - lua_unlock(L); - return 1; -} - - -LUA_API void lua_setuservalue (lua_State *L, int idx) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttisfulluserdata(o), "full userdata expected"); - setuservalue(L, uvalue(o), L->top - 1); - luaC_barrier(L, gcvalue(o), L->top - 1); - L->top--; - lua_unlock(L); -} - - -/* -** 'load' and 'call' functions (run Lua code) -*/ - - -#define checkresults(L,na,nr) \ - api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ - "results from function overflow current stack size") - - -LUA_API void lua_callk (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k) { - StkId func; - lua_lock(L); - api_check(L, k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); - checkresults(L, nargs, nresults); - func = L->top - (nargs+1); - if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ - L->ci->u.c.k = k; /* save continuation */ - L->ci->u.c.ctx = ctx; /* save context */ - luaD_call(L, func, nresults); /* do the call */ - } - else /* no continuation or no yieldable */ - luaD_callnoyield(L, func, nresults); /* just do the call */ - adjustresults(L, nresults); - lua_unlock(L); -} - - - -/* -** Execute a protected call. -*/ -struct CallS { /* data to 'f_call' */ - StkId func; - int nresults; -}; - - -static void f_call (lua_State *L, void *ud) { - struct CallS *c = cast(struct CallS *, ud); - luaD_callnoyield(L, c->func, c->nresults); -} - - - -LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k) { - struct CallS c; - int status; - ptrdiff_t func; - lua_lock(L); - api_check(L, k == NULL || !isLua(L->ci), - "cannot use continuations inside hooks"); - api_checknelems(L, nargs+1); - api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); - checkresults(L, nargs, nresults); - if (errfunc == 0) - func = 0; - else { - StkId o = index2addr(L, errfunc); - api_checkstackindex(L, errfunc, o); - func = savestack(L, o); - } - c.func = L->top - (nargs+1); /* function to be called */ - if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ - c.nresults = nresults; /* do a 'conventional' protected call */ - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); - } - else { /* prepare continuation (call is already protected by 'resume') */ - CallInfo *ci = L->ci; - ci->u.c.k = k; /* save continuation */ - ci->u.c.ctx = ctx; /* save context */ - /* save information for error recovery */ - ci->extra = savestack(L, c.func); - ci->u.c.old_errfunc = L->errfunc; - L->errfunc = func; - setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ - ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ - luaD_call(L, c.func, nresults); /* do the call */ - ci->callstatus &= ~CIST_YPCALL; - L->errfunc = ci->u.c.old_errfunc; - status = LUA_OK; /* if it is here, there were no errors */ - } - adjustresults(L, nresults); - lua_unlock(L); - return status; -} - - -LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, - const char *chunkname, const char *mode) { - ZIO z; - int status; - lua_lock(L); - if (!chunkname) chunkname = "?"; - luaZ_init(L, &z, reader, data); - status = luaD_protectedparser(L, &z, chunkname, mode); - if (status == LUA_OK) { /* no errors? */ - LClosure *f = clLvalue(L->top - 1); /* get newly created function */ - if (f->nupvalues >= 1) { /* does it have an upvalue? */ - /* get global table from registry */ - Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ - setobj(L, f->upvals[0]->v, gt); - luaC_upvalbarrier(L, f->upvals[0]); - } - } - lua_unlock(L); - return status; -} - - -LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { - int status; - TValue *o; - lua_lock(L); - api_checknelems(L, 1); - o = L->top - 1; - if (isLfunction(o)) - status = luaU_dump(L, getproto(o), writer, data, strip); - else - status = 1; - lua_unlock(L); - return status; -} - - -LUA_API int lua_status (lua_State *L) { - return L->status; -} - - -/* -** Garbage-collection function -*/ - -LUA_API int lua_gc (lua_State *L, int what, int data) { - int res = 0; - global_State *g; - lua_lock(L); - g = G(L); - switch (what) { - case LUA_GCSTOP: { - g->gcrunning = 0; - break; - } - case LUA_GCRESTART: { - luaE_setdebt(g, 0); - g->gcrunning = 1; - break; - } - case LUA_GCCOLLECT: { - luaC_fullgc(L, 0); - break; - } - case LUA_GCCOUNT: { - /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast_int(gettotalbytes(g) >> 10); - break; - } - case LUA_GCCOUNTB: { - res = cast_int(gettotalbytes(g) & 0x3ff); - break; - } - case LUA_GCSTEP: { - l_mem debt = 1; /* =1 to signal that it did an actual step */ - lu_byte oldrunning = g->gcrunning; - g->gcrunning = 1; /* allow GC to run */ - if (data == 0) { - luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ - luaC_step(L); - } - else { /* add 'data' to total debt */ - debt = cast(l_mem, data) * 1024 + g->GCdebt; - luaE_setdebt(g, debt); - luaC_checkGC(L); - } - g->gcrunning = oldrunning; /* restore previous state */ - if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ - break; - } - case LUA_GCSETPAUSE: { - res = g->gcpause; - g->gcpause = data; - break; - } - case LUA_GCSETSTEPMUL: { - res = g->gcstepmul; - if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ - g->gcstepmul = data; - break; - } - case LUA_GCISRUNNING: { - res = g->gcrunning; - break; - } - default: res = -1; /* invalid option */ - } - lua_unlock(L); - return res; -} - - - -/* -** miscellaneous functions -*/ - - -LUA_API int lua_error (lua_State *L) { - lua_lock(L); - api_checknelems(L, 1); - luaG_errormsg(L); - /* code unreachable; will unlock when control actually leaves the kernel */ - return 0; /* to avoid warnings */ -} - - -LUA_API int lua_next (lua_State *L, int idx) { - StkId t; - int more; - lua_lock(L); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - more = luaH_next(L, hvalue(t), L->top - 1); - if (more) { - api_incr_top(L); - } - else /* no more elements */ - L->top -= 1; /* remove key */ - lua_unlock(L); - return more; -} - - -LUA_API void lua_concat (lua_State *L, int n) { - lua_lock(L); - api_checknelems(L, n); - if (n >= 2) { - luaV_concat(L, n); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); - api_incr_top(L); - } - /* else n == 1; nothing to do */ - luaC_checkGC(L); - lua_unlock(L); -} - - -LUA_API void lua_len (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = index2addr(L, idx); - luaV_objlen(L, L->top, t); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { - lua_Alloc f; - lua_lock(L); - if (ud) *ud = G(L)->ud; - f = G(L)->frealloc; - lua_unlock(L); - return f; -} - - -LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { - lua_lock(L); - G(L)->ud = ud; - G(L)->frealloc = f; - lua_unlock(L); -} - - -LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - Udata *u; - lua_lock(L); - u = luaS_newudata(L, size); - setuvalue(L, L->top, u); - api_incr_top(L); - luaC_checkGC(L); - lua_unlock(L); - return getudatamem(u); -} - - - -static const char *aux_upvalue (StkId fi, int n, TValue **val, - CClosure **owner, UpVal **uv) { - switch (ttype(fi)) { - case LUA_TCCL: { /* C closure */ - CClosure *f = clCvalue(fi); - if (!(1 <= n && n <= f->nupvalues)) return NULL; - *val = &f->upvalue[n-1]; - if (owner) *owner = f; - return ""; - } - case LUA_TLCL: { /* Lua closure */ - LClosure *f = clLvalue(fi); - TString *name; - Proto *p = f->p; - if (!(1 <= n && n <= p->sizeupvalues)) return NULL; - *val = f->upvals[n-1]->v; - if (uv) *uv = f->upvals[n - 1]; - name = p->upvalues[n-1].name; - return (name == NULL) ? "(*no name)" : getstr(name); - } - default: return NULL; /* not a closure */ - } -} - - -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); - if (name) { - setobj2s(L, L->top, val); - api_incr_top(L); - } - lua_unlock(L); - return name; -} - - -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TValue *val = NULL; /* to avoid warnings */ - CClosure *owner = NULL; - UpVal *uv = NULL; - StkId fi; - lua_lock(L); - fi = index2addr(L, funcindex); - api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner, &uv); - if (name) { - L->top--; - setobj(L, val, L->top); - if (owner) { luaC_barrier(L, owner, L->top); } - else if (uv) { luaC_upvalbarrier(L, uv); } - } - lua_unlock(L); - return name; -} - - -static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { - LClosure *f; - StkId fi = index2addr(L, fidx); - api_check(L, ttisLclosure(fi), "Lua function expected"); - f = clLvalue(fi); - api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); - if (pf) *pf = f; - return &f->upvals[n - 1]; /* get its upvalue pointer */ -} - - -LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { - StkId fi = index2addr(L, fidx); - switch (ttype(fi)) { - case LUA_TLCL: { /* lua closure */ - return *getupvalref(L, fidx, n, NULL); - } - case LUA_TCCL: { /* C closure */ - CClosure *f = clCvalue(fi); - api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); - return &f->upvalue[n - 1]; - } - default: { - api_check(L, 0, "closure expected"); - return NULL; - } - } -} - - -LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, - int fidx2, int n2) { - LClosure *f1; - UpVal **up1 = getupvalref(L, fidx1, n1, &f1); - UpVal **up2 = getupvalref(L, fidx2, n2, NULL); - luaC_upvdeccount(L, *up1); - *up1 = *up2; - (*up1)->refcount++; - if (upisopen(*up1)) (*up1)->u.open.touched = 1; - luaC_upvalbarrier(L, *up1); -} - - +/* +** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" + + + +const char lua_ident[] = + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; + + +/* value at a non-valid index */ +#define NONVALIDVALUE cast(TValue *, luaO_nilobject) + +/* corresponding test */ +#define isvalid(o) ((o) != luaO_nilobject) + +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for upvalue */ +#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) + +/* test for valid but not pseudo index */ +#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) + +#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index") + +#define api_checkstackindex(l, i, o) \ + api_check(l, isstackindex(i, o), "index not in the stack") + + +static TValue *index2addr (lua_State *L, int idx) { + CallInfo *ci = L->ci; + if (idx > 0) { + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); + if (o >= L->top) return NONVALIDVALUE; + else return o; + } + else if (!ispseudo(idx)) { /* negative index */ + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); + return L->top + idx; + } + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return NONVALIDVALUE; /* it has no upvalues */ + else { + CClosure *func = clCvalue(ci->func); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; + } + } +} + + +/* +** to be called by 'lua_checkstack' in protected mode, to grow stack +** capturing memory errors +*/ +static void growstack (lua_State *L, void *ud) { + int size = *(int *)ud; + luaD_growstack(L, size); +} + + +LUA_API int lua_checkstack (lua_State *L, int n) { + int res; + CallInfo *ci = L->ci; + lua_lock(L); + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last - L->top > n) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else { /* no; need to grow stack */ + int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ + res = 0; /* no */ + else /* try to grow stack */ + res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); + } + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ + lua_unlock(L); + return res; +} + + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, to->top, from->top + i); + to->top++; /* stack already checked by previous 'api_check' */ + } + lua_unlock(to); +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API const lua_Number *lua_version (lua_State *L) { + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + else return G(L)->version; +} + + + +/* +** basic stack manipulation +*/ + + +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || ispseudo(idx)) + ? idx + : cast_int(L->top - L->ci->func) + idx; +} + + +LUA_API int lua_gettop (lua_State *L) { + return cast_int(L->top - (L->ci->func + 1)); +} + + +LUA_API void lua_settop (lua_State *L, int idx) { + StkId func = L->ci->func; + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) + setnilvalue(L->top++); + L->top = (func + 1) + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); + L->top += idx+1; /* 'subtract' index (index is negative) */ + } + lua_unlock(L); +} + + +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +*/ +static void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, from); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } +} + + +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; + lua_lock(L); + t = L->top - 1; /* end of stack segment being rotated */ + p = index2addr(L, idx); /* start of segment */ + api_checkstackindex(L, idx, p); + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ + lua_unlock(L); +} + + +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2addr(L, fromidx); + to = index2addr(L, toidx); + api_checkvalidindex(L, to); + setobj(L, to, fr); + if (isupvalue(toidx)) /* function upvalue? */ + luaC_barrier(L, clCvalue(L->ci->func), fr); + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L, L->top, index2addr(L, idx)); + api_incr_top(L); + lua_unlock(L); +} + + + +/* +** access functions (stack -> C) +*/ + + +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (isvalid(o) ? ttnov(o) : LUA_TNONE); +} + + +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); + return ttypename(t); +} + + +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (ttislcf(o) || (ttisCclosure(o))); +} + + +LUA_API int lua_isinteger (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return ttisinteger(o); +} + + +LUA_API int lua_isnumber (lua_State *L, int idx) { + lua_Number n; + const TValue *o = index2addr(L, idx); + return tonumber(o, &n); +} + + +LUA_API int lua_isstring (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return (ttisstring(o) || cvt2str(o)); +} + + +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return (ttisfulluserdata(o) || ttislightuserdata(o)); +} + + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; +} + + +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top, L->top - 1); + api_incr_top(L); + } + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); + L->top--; /* remove second operand */ + lua_unlock(L); +} + + +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { + StkId o1, o2; + int i = 0; + lua_lock(L); /* may call tag method */ + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + if (isvalid(o1) && isvalid(o2)) { + switch (op) { + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); + } + } + lua_unlock(L); + return i; +} + + +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, L->top); + if (sz != 0) + api_incr_top(L); + return sz; +} + + +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n; + const TValue *o = index2addr(L, idx); + int isnum = tonumber(o, &n); + if (!isnum) + n = 0; /* call to 'tonumber' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return n; +} + + +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res; + const TValue *o = index2addr(L, idx); + int isnum = tointeger(o, &res); + if (!isnum) + res = 0; /* call to 'tointeger' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return res; +} + + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TValue *o = index2addr(L, idx); + return !l_isfalse(o); +} + + +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2addr(L, idx); + if (!ttisstring(o)) { + if (!cvt2str(o)) { /* not convertible? */ + if (len != NULL) *len = 0; + return NULL; + } + lua_lock(L); /* 'luaO_tostring' may create a new string */ + luaO_tostring(L, o); + luaC_checkGC(L); + o = index2addr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + if (len != NULL) + *len = vslen(o); + return svalue(o); +} + + +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttype(o)) { + case LUA_TSHRSTR: return tsvalue(o)->shrlen; + case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + default: return 0; + } +} + + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + if (ttislcf(o)) return fvalue(o); + else if (ttisCclosure(o)) + return clCvalue(o)->f; + else return NULL; /* not a C function */ +} + + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttnov(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); +} + + +LUA_API const void *lua_topointer (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TLCL: return clLvalue(o); + case LUA_TCCL: return clCvalue(o); + case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return NULL; + } +} + + + +/* +** push functions (C -> stack) +*/ + + +LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); + setnilvalue(L->top); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setfltvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setivalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; + lua_lock(L); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getstr(ts); +} + + +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + lua_lock(L); + if (s == NULL) + setnilvalue(L->top); + else { + TString *ts; + ts = luaS_new(L, s); + setsvalue2s(L, L->top, ts); + s = getstr(ts); /* internal copy's address */ + } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; +} + + +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + luaC_checkGC(L); + lua_unlock(L); + return ret; +} + + +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + lua_lock(L); + if (n == 0) { + setfvalue(L->top, fn); + api_incr_top(L); + } + else { + CClosure *cl; + api_checknelems(L, n); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); + cl = luaF_newCclosure(L, n); + cl->f = fn; + L->top -= n; + while (n--) { + setobj2n(L, &cl->upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + } + setclCvalue(L, L->top, cl); + api_incr_top(L); + luaC_checkGC(L); + } + lua_unlock(L); +} + + +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + + +/* +** get functions (Lua -> stack) +*/ + + +static int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top, str); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { + Table *reg = hvalue(&G(L)->l_registry); + lua_lock(L); + return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +} + + +LUA_API int lua_gettable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2addr(L, idx), k); +} + + +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { + StkId t; + const TValue *slot; + lua_lock(L); + t = index2addr(L, idx); + if (luaV_fastget(L, t, n, slot, luaH_getint)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(t), n)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { + StkId t; + TValue k; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setpvalue(&k, cast(void *, p)); + setobj2s(L, L->top, luaH_get(hvalue(t), &k)); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; + lua_lock(L); + t = luaH_new(L); + sethvalue(L, L->top, t); + api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TValue *obj; + Table *mt; + int res = 0; + lua_lock(L); + obj = index2addr(L, objindex); + switch (ttnov(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; + default: + mt = G(L)->mt[ttnov(obj)]; + break; + } + if (mt != NULL) { + sethvalue(L, L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; +} + + +LUA_API int lua_getuservalue (lua_State *L, int idx) { + StkId o; + lua_lock(L); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + getuservalue(L, uvalue(o), L->top); + api_incr_top(L); + lua_unlock(L); + return ttnov(L->top - 1); +} + + +/* +** set functions (stack -> Lua) +*/ + +/* +** t[k] = value at the top of the stack (where 'k' is a string) +*/ +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) + L->top--; /* pop value */ + else { + setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} + + +LUA_API void lua_setglobal (lua_State *L, const char *name) { + Table *reg = hvalue(&G(L)->l_registry); + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); +} + + +LUA_API void lua_settable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2addr(L, idx); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); +} + + +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2addr(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { + StkId t; + const TValue *slot; + lua_lock(L); + api_checknelems(L, 1); + t = index2addr(L, idx); + if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) + L->top--; /* pop value */ + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); +} + + +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId o; + TValue *slot; + lua_lock(L); + api_checknelems(L, 2); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + slot = luaH_set(L, hvalue(o), L->top - 2); + setobj2t(L, slot, L->top - 1); + invalidateTMcache(hvalue(o)); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top -= 2; + lua_unlock(L); +} + + +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + luaH_setint(L, hvalue(o), n, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top-1); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { + StkId o; + TValue k, *slot; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setpvalue(&k, cast(void *, p)); + slot = luaH_set(L, hvalue(o), &k); + setobj2t(L, slot, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top - 1); + L->top--; + lua_unlock(L); +} + + +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TValue *obj; + Table *mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2addr(L, objindex); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1), "table expected"); + mt = hvalue(L->top - 1); + } + switch (ttnov(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->metatable = mt; + if (mt) { + luaC_objbarrier(L, uvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); + } + break; + } + default: { + G(L)->mt[ttnov(obj)] = mt; + break; + } + } + L->top--; + lua_unlock(L); + return 1; +} + + +LUA_API void lua_setuservalue (lua_State *L, int idx) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2addr(L, idx); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + setuservalue(L, uvalue(o), L->top - 1); + luaC_barrier(L, gcvalue(o), L->top - 1); + L->top--; + lua_unlock(L); +} + + +/* +** 'load' and 'call' functions (run Lua code) +*/ + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ + "results from function overflow current stack size") + + +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { + StkId func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + func = L->top - (nargs+1); + if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_callnoyield(L, func, nresults); /* just do the call */ + adjustresults(L, nresults); + lua_unlock(L); +} + + + +/* +** Execute a protected call. +*/ +struct CallS { /* data to 'f_call' */ + StkId func; + int nresults; +}; + + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_callnoyield(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); + api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2addr(L, errfunc); + api_checkstackindex(L, errfunc, o); + func = savestack(L, o); + } + c.func = L->top - (nargs+1); /* function to be called */ + if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->extra = savestack(L, c.func); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } + adjustresults(L, nresults); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, + const char *chunkname, const char *mode) { + ZIO z; + int status; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname, mode); + if (status == LUA_OK) { /* no errors? */ + LClosure *f = clLvalue(L->top - 1); /* get newly created function */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ + /* get global table from registry */ + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, f->upvals[0]->v, gt); + luaC_upvalbarrier(L, f->upvals[0]); + } + } + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { + int status; + TValue *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o)) + status = luaU_dump(L, getproto(o), writer, data, strip); + else + status = 1; + lua_unlock(L); + return status; +} + + +LUA_API int lua_status (lua_State *L) { + return L->status; +} + + +/* +** Garbage-collection function +*/ + +LUA_API int lua_gc (lua_State *L, int what, int data) { + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->gcrunning = 0; + break; + } + case LUA_GCRESTART: { + luaE_setdebt(g, 0); + g->gcrunning = 1; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L, 0); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(gettotalbytes(g) >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(gettotalbytes(g) & 0x3ff); + break; + } + case LUA_GCSTEP: { + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldrunning = g->gcrunning; + g->gcrunning = 1; /* allow GC to run */ + if (data == 0) { + luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ + luaC_step(L); + } + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); + } + g->gcrunning = oldrunning; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ + break; + } + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ + g->gcstepmul = data; + break; + } + case LUA_GCISRUNNING: { + res = g->gcrunning; + break; + } + default: res = -1; /* invalid option */ + } + lua_unlock(L); + return res; +} + + + +/* +** miscellaneous functions +*/ + + +LUA_API int lua_error (lua_State *L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + /* code unreachable; will unlock when control actually leaves the kernel */ + return 0; /* to avoid warnings */ +} + + +LUA_API int lua_next (lua_State *L, int idx) { + StkId t; + int more; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) { + api_incr_top(L); + } + else /* no more elements */ + L->top -= 1; /* remove key */ + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaV_concat(L, n); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + luaC_checkGC(L); + lua_unlock(L); +} + + +LUA_API void lua_len (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_objlen(L, L->top, t); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); + if (ud) *ud = G(L)->ud; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + u = luaS_newudata(L, size); + setuvalue(L, L->top, u); + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return getudatamem(u); +} + + + +static const char *aux_upvalue (StkId fi, int n, TValue **val, + CClosure **owner, UpVal **uv) { + switch (ttype(fi)) { + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (!(1 <= n && n <= f->nupvalues)) return NULL; + *val = &f->upvalue[n-1]; + if (owner) *owner = f; + return ""; + } + case LUA_TLCL: { /* Lua closure */ + LClosure *f = clLvalue(fi); + TString *name; + Proto *p = f->p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->upvals[n-1]->v; + if (uv) *uv = f->upvals[n - 1]; + name = p->upvalues[n-1].name; + return (name == NULL) ? "(*no name)" : getstr(name); + } + default: return NULL; /* not a closure */ + } +} + + +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + lua_lock(L); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); + if (name) { + setobj2s(L, L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TValue *val = NULL; /* to avoid warnings */ + CClosure *owner = NULL; + UpVal *uv = NULL; + StkId fi; + lua_lock(L); + fi = index2addr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, &val, &owner, &uv); + if (name) { + L->top--; + setobj(L, val, L->top); + if (owner) { luaC_barrier(L, owner, L->top); } + else if (uv) { luaC_upvalbarrier(L, uv); } + } + lua_unlock(L); + return name; +} + + +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + LClosure *f; + StkId fi = index2addr(L, fidx); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); + if (pf) *pf = f; + return &f->upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + StkId fi = index2addr(L, fidx); + switch (ttype(fi)) { + case LUA_TLCL: { /* lua closure */ + return *getupvalref(L, fidx, n, NULL); + } + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); + return &f->upvalue[n - 1]; + } + default: { + api_check(L, 0, "closure expected"); + return NULL; + } + } +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + LClosure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + luaC_upvdeccount(L, *up1); + *up1 = *up2; + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.open.touched = 1; + luaC_upvalbarrier(L, *up1); +} + + diff --git a/libs/lua/source/lauxlib.c b/libs/lua/source/lauxlib.c index 8bdada50..4a3e4f1a 100644 --- a/libs/lua/source/lauxlib.c +++ b/libs/lua/source/lauxlib.c @@ -1,1043 +1,1043 @@ -/* -** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - -#define lauxlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include - - -/* -** This file uses only the official API of Lua. -** Any function declared here could be written as an application function. -*/ - -#include "lua.h" - -#include "lauxlib.h" - - -/* -** {====================================================== -** Traceback -** ======================================================= -*/ - - -#define LEVELS1 10 /* size of the first part of the stack */ -#define LEVELS2 11 /* size of the second part of the stack */ - - - -/* -** search for 'objidx' in table at index -1. -** return 1 + string at top if find a good name. -*/ -static int findfield (lua_State *L, int objidx, int level) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - while (lua_next(L, -2)) { /* for each pair in table */ - if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ - if (lua_rawequal(L, objidx, -1)) { /* found object? */ - lua_pop(L, 1); /* remove value (but keep name) */ - return 1; - } - else if (findfield(L, objidx, level - 1)) { /* try recursively */ - lua_remove(L, -2); /* remove table (but keep name) */ - lua_pushliteral(L, "."); - lua_insert(L, -2); /* place '.' between the two names */ - lua_concat(L, 3); - return 1; - } - } - lua_pop(L, 1); /* remove value */ - } - return 0; /* not found */ -} - - -/* -** Search for a name for a function in all loaded modules -*/ -static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - if (findfield(L, top + 1, 2)) { - const char *name = lua_tostring(L, -1); - if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ - lua_pushstring(L, name + 3); /* push name without prefix */ - lua_remove(L, -2); /* remove original name */ - } - lua_copy(L, -1, top + 1); /* move name to proper place */ - lua_pop(L, 2); /* remove pushed values */ - return 1; - } - else { - lua_settop(L, top); /* remove function and global table */ - return 0; - } -} - - -static void pushfuncname (lua_State *L, lua_Debug *ar) { - if (pushglobalfuncname(L, ar)) { /* try first a global name */ - lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else if (*ar->namewhat != '\0') /* is there a name from code? */ - lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what != 'C') /* for Lua functions, use */ - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); - else /* nothing left... */ - lua_pushliteral(L, "?"); -} - - -static int lastlevel (lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - /* find an upper bound */ - while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } - /* do a binary search */ - while (li < le) { - int m = (li + le)/2; - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - return le - 1; -} - - -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level) { - lua_Debug ar; - int top = lua_gettop(L); - int last = lastlevel(L1); - int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; - if (msg) - lua_pushfstring(L, "%s\n", msg); - luaL_checkstack(L, 10, NULL); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (n1-- == 0) { /* too many levels? */ - lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = last - LEVELS2 + 1; /* and skip to last ones */ - } - else { - lua_getinfo(L1, "Slnt", &ar); - lua_pushfstring(L, "\n\t%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - lua_pushliteral(L, " in "); - pushfuncname(L, &ar); - if (ar.istailcall) - lua_pushliteral(L, "\n\t(...tail calls...)"); - lua_concat(L, lua_gettop(L) - top); - } - } - lua_concat(L, lua_gettop(L) - top); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Error-report functions -** ======================================================= -*/ - -LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { - lua_Debug ar; - if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); - lua_getinfo(L, "n", &ar); - if (strcmp(ar.namewhat, "method") == 0) { - arg--; /* do not count 'self' */ - if (arg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling '%s' on bad self (%s)", - ar.name, extramsg); - } - if (ar.name == NULL) - ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to '%s' (%s)", - arg, ar.name, extramsg); -} - - -static int typeerror (lua_State *L, int arg, const char *tname) { - const char *msg; - const char *typearg; /* name for the type of the actual argument */ - if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) - typearg = lua_tostring(L, -1); /* use the given type name */ - else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) - typearg = "light userdata"; /* special name for messages */ - else - typearg = luaL_typename(L, arg); /* standard name */ - msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); - return luaL_argerror(L, arg, msg); -} - - -static void tag_error (lua_State *L, int arg, int tag) { - typeerror(L, arg, lua_typename(L, tag)); -} - - -/* -** The use of 'lua_pushfstring' ensures this function does not -** need reserved stack space when called. -*/ -LUALIB_API void luaL_where (lua_State *L, int level) { - lua_Debug ar; - if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Sl", &ar); /* get info about it */ - if (ar.currentline > 0) { /* is there info? */ - lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); - return; - } - } - lua_pushfstring(L, ""); /* else, no information available... */ -} - - -/* -** Again, the use of 'lua_pushvfstring' ensures this function does -** not need reserved stack space when called. (At worst, it generates -** an error with "stack overflow" instead of the given message.) -*/ -LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - luaL_where(L, 1); - lua_pushvfstring(L, fmt, argp); - va_end(argp); - lua_concat(L, 2); - return lua_error(L); -} - - -LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { - int en = errno; /* calls to Lua API may change this value */ - if (stat) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); - else - lua_pushstring(L, strerror(en)); - lua_pushinteger(L, en); - return 3; - } -} - - -#if !defined(l_inspectstat) /* { */ - -#if defined(LUA_USE_POSIX) - -#include - -/* -** use appropriate macros to interpret 'pclose' return status -*/ -#define l_inspectstat(stat,what) \ - if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ - else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } - -#else - -#define l_inspectstat(stat,what) /* no op */ - -#endif - -#endif /* } */ - - -LUALIB_API int luaL_execresult (lua_State *L, int stat) { - const char *what = "exit"; /* type of termination */ - if (stat == -1) /* error? */ - return luaL_fileresult(L, 0, NULL); - else { - l_inspectstat(stat, what); /* interpret result */ - if (*what == 'e' && stat == 0) /* successful termination? */ - lua_pushboolean(L, 1); - else - lua_pushnil(L); - lua_pushstring(L, what); - lua_pushinteger(L, stat); - return 3; /* return true/nil,what,code */ - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Userdata's metatable manipulation -** ======================================================= -*/ - -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ - return 0; /* leave previous value on top, but return 0 */ - lua_pop(L, 1); - lua_createtable(L, 0, 2); /* create metatable */ - lua_pushstring(L, tname); - lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ - return 1; -} - - -LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} - - -LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - luaL_getmetatable(L, tname); /* get correct metatable */ - if (!lua_rawequal(L, -1, -2)) /* not the same? */ - p = NULL; /* value is a userdata with wrong metatable */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } - } - return NULL; /* value is not a userdata with a metatable */ -} - - -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - void *p = luaL_testudata(L, ud, tname); - if (p == NULL) typeerror(L, ud, tname); - return p; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Argument check functions -** ======================================================= -*/ - -LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, arg, def) : - luaL_checkstring(L, arg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, arg, - lua_pushfstring(L, "invalid option '%s'", name)); -} - - -/* -** Ensures the stack has at least 'space' extra slots, raising an error -** if it cannot fulfill the request. (The error handling needs a few -** extra slots to format the error message. In case of an error without -** this extra space, Lua will generate the same 'stack overflow' error, -** but without 'msg'.) -*/ -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - if (!lua_checkstack(L, space)) { - if (msg) - luaL_error(L, "stack overflow (%s)", msg); - else - luaL_error(L, "stack overflow"); - } -} - - -LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { - if (lua_type(L, arg) != t) - tag_error(L, arg, t); -} - - -LUALIB_API void luaL_checkany (lua_State *L, int arg) { - if (lua_type(L, arg) == LUA_TNONE) - luaL_argerror(L, arg, "value expected"); -} - - -LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { - const char *s = lua_tolstring(L, arg, len); - if (!s) tag_error(L, arg, LUA_TSTRING); - return s; -} - - -LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, - const char *def, size_t *len) { - if (lua_isnoneornil(L, arg)) { - if (len) - *len = (def ? strlen(def) : 0); - return def; - } - else return luaL_checklstring(L, arg, len); -} - - -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { - int isnum; - lua_Number d = lua_tonumberx(L, arg, &isnum); - if (!isnum) - tag_error(L, arg, LUA_TNUMBER); - return d; -} - - -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, arg, def); -} - - -static void interror (lua_State *L, int arg) { - if (lua_isnumber(L, arg)) - luaL_argerror(L, arg, "number has no integer representation"); - else - tag_error(L, arg, LUA_TNUMBER); -} - - -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { - int isnum; - lua_Integer d = lua_tointegerx(L, arg, &isnum); - if (!isnum) { - interror(L, arg); - } - return d; -} - - -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, - lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, arg, def); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -/* userdata to box arbitrary data */ -typedef struct UBox { - void *box; - size_t bsize; -} UBox; - - -static void *resizebox (lua_State *L, int idx, size_t newsize) { - void *ud; - lua_Alloc allocf = lua_getallocf(L, &ud); - UBox *box = (UBox *)lua_touserdata(L, idx); - void *temp = allocf(ud, box->box, box->bsize, newsize); - if (temp == NULL && newsize > 0) { /* allocation error? */ - resizebox(L, idx, 0); /* free buffer */ - luaL_error(L, "not enough memory for buffer allocation"); - } - box->box = temp; - box->bsize = newsize; - return temp; -} - - -static int boxgc (lua_State *L) { - resizebox(L, 1, 0); - return 0; -} - - -static void *newbox (lua_State *L, size_t newsize) { - UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); - box->box = NULL; - box->bsize = 0; - if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ - lua_pushcfunction(L, boxgc); - lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ - } - lua_setmetatable(L, -2); - return resizebox(L, -1, newsize); -} - - -/* -** check whether buffer is using a userdata on the stack as a temporary -** buffer -*/ -#define buffonstack(B) ((B)->b != (B)->initb) - - -/* -** returns a pointer to a free area with at least 'sz' bytes -*/ -LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { - lua_State *L = B->L; - if (B->size - B->n < sz) { /* not enough space? */ - char *newbuff; - size_t newsize = B->size * 2; /* double buffer size */ - if (newsize - B->n < sz) /* not big enough? */ - newsize = B->n + sz; - if (newsize < B->n || newsize - B->n < sz) - luaL_error(L, "buffer too large"); - /* create larger buffer */ - if (buffonstack(B)) - newbuff = (char *)resizebox(L, -1, newsize); - else { /* no buffer yet */ - newbuff = (char *)newbox(L, newsize); - memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ - } - B->b = newbuff; - B->size = newsize; - } - return &B->b[B->n]; -} - - -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ - char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); - } -} - - -LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { - luaL_addlstring(B, s, strlen(s)); -} - - -LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - lua_State *L = B->L; - lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) { - resizebox(L, -2, 0); /* delete old buffer */ - lua_remove(L, -2); /* remove its header from the stack */ - } -} - - -LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { - luaL_addsize(B, sz); - luaL_pushresult(B); -} - - -LUALIB_API void luaL_addvalue (luaL_Buffer *B) { - lua_State *L = B->L; - size_t l; - const char *s = lua_tolstring(L, -1, &l); - if (buffonstack(B)) - lua_insert(L, -2); /* put value below buffer */ - luaL_addlstring(B, s, l); - lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ -} - - -LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - B->L = L; - B->b = B->initb; - B->n = 0; - B->size = LUAL_BUFFERSIZE; -} - - -LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { - luaL_buffinit(L, B); - return luaL_prepbuffsize(B, sz); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Reference system -** ======================================================= -*/ - -/* index of free-list header */ -#define freelist 0 - - -LUALIB_API int luaL_ref (lua_State *L, int t) { - int ref; - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* 'nil' has a unique fixed reference */ - } - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); /* get first free element */ - ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ - lua_pop(L, 1); /* remove it from stack */ - if (ref != 0) { /* any free element? */ - lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ - } - else /* no free elements */ - ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - lua_rawseti(L, t, ref); - return ref; -} - - -LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { - if (ref >= 0) { - t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); - lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ - lua_pushinteger(L, ref); - lua_rawseti(L, t, freelist); /* t[freelist] = ref */ - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Load functions -** ======================================================= -*/ - -typedef struct LoadF { - int n; /* number of pre-read characters */ - FILE *f; /* file being read */ - char buff[BUFSIZ]; /* area for reading file */ -} LoadF; - - -static const char *getF (lua_State *L, void *ud, size_t *size) { - LoadF *lf = (LoadF *)ud; - (void)L; /* not used */ - if (lf->n > 0) { /* are there pre-read characters to be read? */ - *size = lf->n; /* return them (chars already in buffer) */ - lf->n = 0; /* no more pre-read characters */ - } - else { /* read a block from file */ - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'getF' called 'fread', it might still wait for user input. - The next check avoids this problem. */ - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ - } - return lf->buff; -} - - -static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); - const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; -} - - -static int skipBOM (LoadF *lf) { - const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ - int c; - lf->n = 0; - do { - c = getc(lf->f); - if (c == EOF || c != *(const unsigned char *)p++) return c; - lf->buff[lf->n++] = c; /* to be read by the parser */ - } while (*p != '\0'); - lf->n = 0; /* prefix matched; discard it */ - return getc(lf->f); /* return next character */ -} - - -/* -** reads the first character of file 'f' and skips an optional BOM mark -** in its beginning plus its first line if it starts with '#'. Returns -** true if it skipped the first line. In any case, '*cp' has the -** first "valid" character of the file (after the optional BOM and -** a first-line comment). -*/ -static int skipcomment (LoadF *lf, int *cp) { - int c = *cp = skipBOM(lf); - if (c == '#') { /* first line is a comment (Unix exec. file)? */ - do { /* skip first line */ - c = getc(lf->f); - } while (c != EOF && c != '\n'); - *cp = getc(lf->f); /* skip end-of-line, if present */ - return 1; /* there was a comment */ - } - else return 0; /* no comment */ -} - - -LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, - const char *mode) { - LoadF lf; - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); - lf.f = fopen(filename, "r"); - if (lf.f == NULL) return errfile(L, "open", fnameindex); - } - if (skipcomment(&lf, &c)) /* read initial portion */ - lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - skipcomment(&lf, &c); /* re-read initial portion */ - } - if (c != EOF) - lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ - status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); - readstatus = ferror(lf.f); - if (filename) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return errfile(L, "read", fnameindex); - } - lua_remove(L, fnameindex); - return status; -} - - -typedef struct LoadS { - const char *s; - size_t size; -} LoadS; - - -static const char *getS (lua_State *L, void *ud, size_t *size) { - LoadS *ls = (LoadS *)ud; - (void)L; /* not used */ - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; -} - - -LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, - const char *name, const char *mode) { - LoadS ls; - ls.s = buff; - ls.size = size; - return lua_load(L, getS, &ls, name, mode); -} - - -LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { - return luaL_loadbuffer(L, s, strlen(s), s); -} - -/* }====================================================== */ - - - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return LUA_TNIL; - else { - int tt; - lua_pushstring(L, event); - tt = lua_rawget(L, -2); - if (tt == LUA_TNIL) /* is metafield nil? */ - lua_pop(L, 2); /* remove metatable and metafield */ - else - lua_remove(L, -2); /* remove only metatable */ - return tt; /* return metafield type */ - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = lua_absindex(L, obj); - if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { - lua_Integer l; - int isnum; - lua_len(L, idx); - l = lua_tointegerx(L, -1, &isnum); - if (!isnum) - luaL_error(L, "object length is not an integer"); - lua_pop(L, 1); /* remove object */ - return l; -} - - -LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { - if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ - if (!lua_isstring(L, -1)) - luaL_error(L, "'__tostring' must return a string"); - } - else { - switch (lua_type(L, idx)) { - case LUA_TNUMBER: { - if (lua_isinteger(L, idx)) - lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); - else - lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); - break; - } - case LUA_TSTRING: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: { - int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ - const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : - luaL_typename(L, idx); - lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); - if (tt != LUA_TNIL) - lua_remove(L, -2); /* remove '__name' */ - break; - } - } - } - return lua_tolstring(L, -1, len); -} - - -/* -** {====================================================== -** Compatibility with 5.1 module functions -** ======================================================= -*/ -#if defined(LUA_COMPAT_MODULE) - -static const char *luaL_findtable (lua_State *L, int idx, - const char *fname, int szhint) { - const char *e; - if (idx) lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, e - fname); - if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, e - fname); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } - else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (*e == '.'); - return NULL; -} - - -/* -** Count number of elements in a luaL_Reg list. -*/ -static int libsize (const luaL_Reg *l) { - int size = 0; - for (; l && l->name; l++) size++; - return size; -} - - -/* -** Find or create a module table with a given name. The function -** first looks at the LOADED table and, if that fails, try a -** global variable with that name. In any case, leaves on the stack -** the module table. -*/ -LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, - int sizehint) { - luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1); - if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - lua_pushglobaltable(L); - if (luaL_findtable(L, 0, modname, sizehint) != NULL) - luaL_error(L, "name conflict for module '%s'", modname); - lua_pushvalue(L, -1); - lua_setfield(L, -3, modname); /* LOADED[modname] = new table */ - } - lua_remove(L, -2); /* remove LOADED table */ -} - - -LUALIB_API void luaL_openlib (lua_State *L, const char *libname, - const luaL_Reg *l, int nup) { - luaL_checkversion(L); - if (libname) { - luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ - lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ - } - if (l) - luaL_setfuncs(L, l, nup); - else - lua_pop(L, nup); /* remove upvalues */ -} - -#endif -/* }====================================================== */ - -/* -** set functions from list 'l' into table at top - 'nup'; each -** function gets the 'nup' elements at the top as upvalues. -** Returns with only the table at the stack. -*/ -LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_setfield(L, -(nup + 2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} - - -/* -** ensure that stack[idx][fname] has a table and push that table -** into the stack -*/ -LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - if (lua_getfield(L, idx, fname) == LUA_TTABLE) - return 1; /* table already there */ - else { - lua_pop(L, 1); /* remove previous result */ - idx = lua_absindex(L, idx); - lua_newtable(L); - lua_pushvalue(L, -1); /* copy to be left at top */ - lua_setfield(L, idx, fname); /* assign new table to field */ - return 0; /* false, because did not find table there */ - } -} - - -/* -** Stripped-down 'require': After checking "loaded" table, calls 'openf' -** to open a module, registers the result in 'package.loaded' table and, -** if 'glb' is true, also registers the result in the global table. -** Leaves resulting module on the top. -*/ -LUALIB_API void luaL_requiref (lua_State *L, const char *modname, - lua_CFunction openf, int glb) { - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, -1, modname); /* LOADED[modname] */ - if (!lua_toboolean(L, -1)) { /* package not already loaded? */ - lua_pop(L, 1); /* remove field */ - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* call 'openf' to open module */ - lua_pushvalue(L, -1); /* make copy of module (call result) */ - lua_setfield(L, -3, modname); /* LOADED[modname] = module */ - } - lua_remove(L, -2); /* remove LOADED table */ - if (glb) { - lua_pushvalue(L, -1); /* copy of module */ - lua_setglobal(L, modname); /* _G[modname] = module */ - } -} - - -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, - const char *r) { - const char *wild; - size_t l = strlen(p); - luaL_Buffer b; - luaL_buffinit(L, &b); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(&b, s, wild - s); /* push prefix */ - luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after 'p' */ - } - luaL_addstring(&b, s); /* push last suffix */ - luaL_pushresult(&b); - return lua_tostring(L, -1); -} - - -static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; (void)osize; /* not used */ - if (nsize == 0) { - free(ptr); - return NULL; - } - else - return realloc(ptr, nsize); -} - - -static int panic (lua_State *L) { - lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return 0; /* return to Lua to abort */ -} - - -LUALIB_API lua_State *luaL_newstate (void) { - lua_State *L = lua_newstate(l_alloc, NULL); - if (L) lua_atpanic(L, &panic); - return L; -} - - -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { - const lua_Number *v = lua_version(L); - if (sz != LUAL_NUMSIZES) /* check numeric types */ - luaL_error(L, "core and library have incompatible numeric types"); - if (v != lua_version(NULL)) - luaL_error(L, "multiple Lua VMs detected"); - else if (*v != ver) - luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", - (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v); -} - +/* +** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + + +/* +** This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +*/ + +#include "lua.h" + +#include "lauxlib.h" + + +/* +** {====================================================== +** Traceback +** ======================================================= +*/ + + +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ + + + +/* +** search for 'objidx' in table at index -1. +** return 1 + string at top if find a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +/* +** Search for a name for a function in all loaded modules +*/ +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what != 'C') /* for Lua functions, use */ + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); +} + + +static int lastlevel (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int last = lastlevel(L1); + int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + if (msg) + lua_pushfstring(L, "%s\n", msg); + luaL_checkstack(L, 10, NULL); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (n1-- == 0) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = last - LEVELS2 + 1; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + pushfuncname(L, &ar); + if (ar.istailcall) + lua_pushliteral(L, "\n\t(...tail calls...)"); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { + lua_Debug ar; + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", + ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); +} + + +static int typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); +} + + +static void tag_error (lua_State *L, int arg, int tag) { + typeerror(L, arg, lua_typename(L, tag)); +} + + +/* +** The use of 'lua_pushfstring' ensures this function does not +** need reserved stack space when called. +*/ +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushfstring(L, ""); /* else, no information available... */ +} + + +/* +** Again, the use of 'lua_pushvfstring' ensures this function does +** not need reserved stack space when called. (At worst, it generates +** an error with "stack overflow" instead of the given message.) +*/ +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + + +LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + int en = errno; /* calls to Lua API may change this value */ + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushstring(L, strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#if !defined(l_inspectstat) /* { */ + +#if defined(LUA_USE_POSIX) + +#include + +/* +** use appropriate macros to interpret 'pclose' return status +*/ +#define l_inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } + +#else + +#define l_inspectstat(stat,what) /* no op */ + +#endif + +#endif /* } */ + + +LUALIB_API int luaL_execresult (lua_State *L, int stat) { + const char *what = "exit"; /* type of termination */ + if (stat == -1) /* error? */ + return luaL_fileresult(L, 0, NULL); + else { + l_inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; /* return true/nil,what,code */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ + return 1; +} + + +LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + if (p == NULL) typeerror(L, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); +} + + +/* +** Ensures the stack has at least 'space' extra slots, raising an error +** if it cannot fulfill the request. (The error handling needs a few +** extra slots to format the error message. In case of an error without +** this extra space, Lua will generate the same 'stack overflow' error, +** but without 'msg'.) +*/ +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { + if (!lua_checkstack(L, space)) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } +} + + +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (lua_type(L, arg) != t) + tag_error(L, arg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNONE) + luaL_argerror(L, arg, "value expected"); +} + + +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (!s) tag_error(L, arg, LUA_TSTRING); + return s; +} + + +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, arg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checklstring(L, arg, len); +} + + +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { + int isnum; + lua_Number d = lua_tonumberx(L, arg, &isnum); + if (!isnum) + tag_error(L, arg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); +} + + +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); +} + + +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { + int isnum; + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (!isnum) { + interror(L, arg); + } + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, arg, def); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + +/* userdata to box arbitrary data */ +typedef struct UBox { + void *box; + size_t bsize; +} UBox; + + +static void *resizebox (lua_State *L, int idx, size_t newsize) { + void *ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox *box = (UBox *)lua_touserdata(L, idx); + void *temp = allocf(ud, box->box, box->bsize, newsize); + if (temp == NULL && newsize > 0) { /* allocation error? */ + resizebox(L, idx, 0); /* free buffer */ + luaL_error(L, "not enough memory for buffer allocation"); + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static void *newbox (lua_State *L, size_t newsize) { + UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ + lua_pushcfunction(L, boxgc); + lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ + } + lua_setmetatable(L, -2); + return resizebox(L, -1, newsize); +} + + +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) + + +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + lua_State *L = B->L; + if (B->size - B->n < sz) { /* not enough space? */ + char *newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not big enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "buffer too large"); + /* create larger buffer */ + if (buffonstack(B)) + newbuff = (char *)resizebox(L, -1, newsize); + else { /* no buffer yet */ + newbuff = (char *)newbox(L, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } + B->b = newbuff; + B->size = newsize; + } + return &B->b[B->n]; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + lua_State *L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) { + resizebox(L, -2, 0); /* delete old buffer */ + lua_remove(L, -2); /* remove its header from the stack */ + } +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t l; + const char *s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* index of free-list header */ +#define freelist 0 + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ + } + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ + } + else /* no free elements */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = lua_absindex(L, t); + lua_rawgeti(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ + lua_pushinteger(L, ref); + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[BUFSIZ]; /* area for reading file */ +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +static int skipBOM (LoadF *lf) { + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char *)p++) return c; + lf->buff[lf->n++] = c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int skipcomment (LoadF *lf, int *cp) { + int c = *cp = skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, "open", fnameindex); + } + if (skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; /* not used */ + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, + const char *name, const char *mode) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name, mode); +} + + +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + +/* }====================================================== */ + + + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return LUA_TNIL; + else { + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = lua_absindex(L, obj); + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; + int isnum; + lua_len(L, idx); + l = lua_tointegerx(L, -1, &isnum); + if (!isnum) + luaL_error(L, "object length is not an integer"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + else { + switch (lua_type(L, idx)) { + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx)); + break; + } + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: { + int tt = luaL_getmetafield(L, idx, "__name"); /* try name */ + const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : + luaL_typename(L, idx); + lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_remove(L, -2); /* remove '__name' */ + break; + } + } + } + return lua_tolstring(L, -1, len); +} + + +/* +** {====================================================== +** Compatibility with 5.1 module functions +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +static const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + if (idx) lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + +/* +** Count number of elements in a luaL_Reg list. +*/ +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l && l->name; l++) size++; + return size; +} + + +/* +** Find or create a module table with a given name. The function +** first looks at the LOADED table and, if that fails, try a +** global variable with that name. In any case, leaves on the stack +** the module table. +*/ +LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, + int sizehint) { + luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1); + if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, modname, sizehint) != NULL) + luaL_error(L, "name conflict for module '%s'", modname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); /* LOADED[modname] = new table */ + } + lua_remove(L, -2); /* remove LOADED table */ +} + + +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { + luaL_checkversion(L); + if (libname) { + luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ + } + if (l) + luaL_setfuncs(L, l, nup); + else + lua_pop(L, nup); /* remove upvalues */ +} + +#endif +/* }====================================================== */ + +/* +** set functions from list 'l' into table at top - 'nup'; each +** function gets the 'nup' elements at the top as upvalues. +** Returns with only the table at the stack. +*/ +LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_setfield(L, -(nup + 2), l->name); + } + lua_pop(L, nup); /* remove upvalues */ +} + + +/* +** ensure that stack[idx][fname] has a table and push that table +** into the stack +*/ +LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ + else { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } +} + + +/* +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. +** Leaves resulting module on the top. +*/ +LUALIB_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, -1, modname); /* LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove LOADED table */ + if (glb) { + lua_pushvalue(L, -1); /* copy of module */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after 'p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; (void)osize; /* not used */ + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +static int panic (lua_State *L) { + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; /* return to Lua to abort */ +} + + +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + if (L) lua_atpanic(L, &panic); + return L; +} + + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { + const lua_Number *v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); + if (v != lua_version(NULL)) + luaL_error(L, "multiple Lua VMs detected"); + else if (*v != ver) + luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", + (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v); +} + diff --git a/libs/lua/source/lbaselib.c b/libs/lua/source/lbaselib.c index 6460e4f8..1ed614f6 100644 --- a/libs/lua/source/lbaselib.c +++ b/libs/lua/source/lbaselib.c @@ -1,498 +1,498 @@ -/* -** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $ -** Basic library -** See Copyright Notice in lua.h -*/ - -#define lbaselib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -static int luaB_print (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - lua_getglobal(L, "tostring"); - for (i=1; i<=n; i++) { - const char *s; - size_t l; - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - s = lua_tolstring(L, -1, &l); /* get result */ - if (s == NULL) - return luaL_error(L, "'tostring' must return a string to 'print'"); - if (i>1) lua_writestring("\t", 1); - lua_writestring(s, l); - lua_pop(L, 1); /* pop result */ - } - lua_writeline(); - return 0; -} - - -#define SPACECHARS " \f\n\r\t\v" - -static const char *b_str2int (const char *s, int base, lua_Integer *pn) { - lua_Unsigned n = 0; - int neg = 0; - s += strspn(s, SPACECHARS); /* skip initial spaces */ - if (*s == '-') { s++; neg = 1; } /* handle signal */ - else if (*s == '+') s++; - if (!isalnum((unsigned char)*s)) /* no digit? */ - return NULL; - do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' - : (toupper((unsigned char)*s) - 'A') + 10; - if (digit >= base) return NULL; /* invalid numeral */ - n = n * base + digit; - s++; - } while (isalnum((unsigned char)*s)); - s += strspn(s, SPACECHARS); /* skip trailing spaces */ - *pn = (lua_Integer)((neg) ? (0u - n) : n); - return s; -} - - -static int luaB_tonumber (lua_State *L) { - if (lua_isnoneornil(L, 2)) { /* standard conversion? */ - luaL_checkany(L, 1); - if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ - lua_settop(L, 1); /* yes; return it */ - return 1; - } - else { - size_t l; - const char *s = lua_tolstring(L, 1, &l); - if (s != NULL && lua_stringtonumber(L, s) == l + 1) - return 1; /* successful conversion to number */ - /* else not a number */ - } - } - else { - size_t l; - const char *s; - lua_Integer n = 0; /* to avoid warnings */ - lua_Integer base = luaL_checkinteger(L, 2); - luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ - s = lua_tolstring(L, 1, &l); - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - if (b_str2int(s, (int)base, &n) == s + l) { - lua_pushinteger(L, n); - return 1; - } /* else not a number */ - } /* else not a number */ - lua_pushnil(L); /* not a number */ - return 1; -} - - -static int luaB_error (lua_State *L) { - int level = (int)luaL_optinteger(L, 2, 1); - lua_settop(L, 1); - if (lua_type(L, 1) == LUA_TSTRING && level > 0) { - luaL_where(L, level); /* add extra information */ - lua_pushvalue(L, 1); - lua_concat(L, 2); - } - return lua_error(L); -} - - -static int luaB_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); - return 1; /* no metatable */ - } - luaL_getmetafield(L, 1, "__metatable"); - return 1; /* returns either __metatable field (if present) or metatable */ -} - - -static int luaB_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) - return luaL_error(L, "cannot change a protected metatable"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; -} - - -static int luaB_rawequal (lua_State *L) { - luaL_checkany(L, 1); - luaL_checkany(L, 2); - lua_pushboolean(L, lua_rawequal(L, 1, 2)); - return 1; -} - - -static int luaB_rawlen (lua_State *L) { - int t = lua_type(L, 1); - luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, - "table or string expected"); - lua_pushinteger(L, lua_rawlen(L, 1)); - return 1; -} - - -static int luaB_rawget (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_rawget(L, 1); - return 1; -} - -static int luaB_rawset (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - luaL_checkany(L, 3); - lua_settop(L, 3); - lua_rawset(L, 1); - return 1; -} - - -static int luaB_collectgarbage (lua_State *L) { - static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", - "isrunning", NULL}; - static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCISRUNNING}; - int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = (int)luaL_optinteger(L, 2, 0); - int res = lua_gc(L, o, ex); - switch (o) { - case LUA_GCCOUNT: { - int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); - return 1; - } - case LUA_GCSTEP: case LUA_GCISRUNNING: { - lua_pushboolean(L, res); - return 1; - } - default: { - lua_pushinteger(L, res); - return 1; - } - } -} - - -static int luaB_type (lua_State *L) { - int t = lua_type(L, 1); - luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); - lua_pushstring(L, lua_typename(L, t)); - return 1; -} - - -static int pairsmeta (lua_State *L, const char *method, int iszero, - lua_CFunction iter) { - luaL_checkany(L, 1); - if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ - lua_pushcfunction(L, iter); /* will return generator, */ - lua_pushvalue(L, 1); /* state, */ - if (iszero) lua_pushinteger(L, 0); /* and initial value */ - else lua_pushnil(L); - } - else { - lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua_call(L, 1, 3); /* get 3 values from metamethod */ - } - return 3; -} - - -static int luaB_next (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 2); /* create a 2nd argument if there isn't one */ - if (lua_next(L, 1)) - return 2; - else { - lua_pushnil(L); - return 1; - } -} - - -static int luaB_pairs (lua_State *L) { - return pairsmeta(L, "__pairs", 0, luaB_next); -} - - -/* -** Traversal function for 'ipairs' -*/ -static int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; - lua_pushinteger(L, i); - return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; -} - - -/* -** 'ipairs' function. Returns 'ipairsaux', given "table", 0. -** (The given "table" may not be a table.) -*/ -static int luaB_ipairs (lua_State *L) { -#if defined(LUA_COMPAT_IPAIRS) - return pairsmeta(L, "__ipairs", 1, ipairsaux); -#else - luaL_checkany(L, 1); - lua_pushcfunction(L, ipairsaux); /* iteration function */ - lua_pushvalue(L, 1); /* state */ - lua_pushinteger(L, 0); /* initial value */ - return 3; -#endif -} - - -static int load_aux (lua_State *L, int status, int envidx) { - if (status == LUA_OK) { - if (envidx != 0) { /* 'env' parameter? */ - lua_pushvalue(L, envidx); /* environment for loaded function */ - if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ - lua_pop(L, 1); /* remove 'env' if not used by previous call */ - } - return 1; - } - else { /* error (message is on top of the stack) */ - lua_pushnil(L); - lua_insert(L, -2); /* put before error message */ - return 2; /* return nil plus error message */ - } -} - - -static int luaB_loadfile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - const char *mode = luaL_optstring(L, 2, NULL); - int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ - int status = luaL_loadfilex(L, fname, mode); - return load_aux(L, status, env); -} - - -/* -** {====================================================== -** Generic Read function -** ======================================================= -*/ - - -/* -** reserved slot, above all arguments, to hold a copy of the returned -** string to avoid it being collected while parsed. 'load' has four -** optional arguments (chunk, source name, mode, and environment). -*/ -#define RESERVEDSLOT 5 - - -/* -** Reader for generic 'load' function: 'lua_load' uses the -** stack for internal stuff, so the reader cannot change the -** stack top. Instead, it keeps its resulting string in a -** reserved slot inside the stack. -*/ -static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - (void)(ud); /* not used */ - luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, 1); /* get function */ - lua_call(L, 0, 1); /* call it */ - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* pop result */ - *size = 0; - return NULL; - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "reader function must return a string"); - lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ - return lua_tolstring(L, RESERVEDSLOT, size); -} - - -static int luaB_load (lua_State *L) { - int status; - size_t l; - const char *s = lua_tolstring(L, 1, &l); - const char *mode = luaL_optstring(L, 3, "bt"); - int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ - if (s != NULL) { /* loading a string? */ - const char *chunkname = luaL_optstring(L, 2, s); - status = luaL_loadbufferx(L, s, l, chunkname, mode); - } - else { /* loading from a reader function */ - const char *chunkname = luaL_optstring(L, 2, "=(load)"); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, RESERVEDSLOT); /* create reserved slot */ - status = lua_load(L, generic_reader, NULL, chunkname, mode); - } - return load_aux(L, status, env); -} - -/* }====================================================== */ - - -static int dofilecont (lua_State *L, int d1, lua_KContext d2) { - (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ - return lua_gettop(L) - 1; -} - - -static int luaB_dofile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) - return lua_error(L); - lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); - return dofilecont(L, 0, 0); -} - - -static int luaB_assert (lua_State *L) { - if (lua_toboolean(L, 1)) /* condition is true? */ - return lua_gettop(L); /* return all arguments */ - else { /* error */ - luaL_checkany(L, 1); /* there must be a condition */ - lua_remove(L, 1); /* remove it */ - lua_pushliteral(L, "assertion failed!"); /* default message */ - lua_settop(L, 1); /* leave only message (default if no other one) */ - return luaB_error(L); /* call 'error' */ - } -} - - -static int luaB_select (lua_State *L) { - int n = lua_gettop(L); - if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { - lua_pushinteger(L, n-1); - return 1; - } - else { - lua_Integer i = luaL_checkinteger(L, 1); - if (i < 0) i = n + i; - else if (i > n) i = n; - luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - (int)i; - } -} - - -/* -** Continuation function for 'pcall' and 'xpcall'. Both functions -** already pushed a 'true' before doing the call, so in case of success -** 'finishpcall' only has to return everything in the stack minus -** 'extra' values (where 'extra' is exactly the number of items to be -** ignored). -*/ -static int finishpcall (lua_State *L, int status, lua_KContext extra) { - if (status != LUA_OK && status != LUA_YIELD) { /* error? */ - lua_pushboolean(L, 0); /* first result (false) */ - lua_pushvalue(L, -2); /* error message */ - return 2; /* return false, msg */ - } - else - return lua_gettop(L) - (int)extra; /* return all results */ -} - - -static int luaB_pcall (lua_State *L) { - int status; - luaL_checkany(L, 1); - lua_pushboolean(L, 1); /* first result if no errors */ - lua_insert(L, 1); /* put it in place */ - status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); - return finishpcall(L, status, 0); -} - - -/* -** Do a protected call with error handling. After 'lua_rotate', the -** stack will have ; so, the function passes -** 2 to 'finishpcall' to skip the 2 first values when returning results. -*/ -static int luaB_xpcall (lua_State *L) { - int status; - int n = lua_gettop(L); - luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ - lua_pushboolean(L, 1); /* first result */ - lua_pushvalue(L, 1); /* function */ - lua_rotate(L, 3, 2); /* move them below function's arguments */ - status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); - return finishpcall(L, status, 2); -} - - -static int luaB_tostring (lua_State *L) { - luaL_checkany(L, 1); - luaL_tolstring(L, 1, NULL); - return 1; -} - - -static const luaL_Reg base_funcs[] = { - {"assert", luaB_assert}, - {"collectgarbage", luaB_collectgarbage}, - {"dofile", luaB_dofile}, - {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"ipairs", luaB_ipairs}, - {"loadfile", luaB_loadfile}, - {"load", luaB_load}, -#if defined(LUA_COMPAT_LOADSTRING) - {"loadstring", luaB_load}, -#endif - {"next", luaB_next}, - {"pairs", luaB_pairs}, - {"pcall", luaB_pcall}, - {"print", luaB_print}, - {"rawequal", luaB_rawequal}, - {"rawlen", luaB_rawlen}, - {"rawget", luaB_rawget}, - {"rawset", luaB_rawset}, - {"select", luaB_select}, - {"setmetatable", luaB_setmetatable}, - {"tonumber", luaB_tonumber}, - {"tostring", luaB_tostring}, - {"type", luaB_type}, - {"xpcall", luaB_xpcall}, - /* placeholders */ - {"_G", NULL}, - {"_VERSION", NULL}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_base (lua_State *L) { - /* open lib into global table */ - lua_pushglobaltable(L); - luaL_setfuncs(L, base_funcs, 0); - /* set global _G */ - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_G"); - /* set global _VERSION */ - lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); - return 1; -} - +/* +** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + size_t l; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tolstring(L, -1, &l); /* get result */ + if (s == NULL) + return luaL_error(L, "'tostring' must return a string to 'print'"); + if (i>1) lua_writestring("\t", 1); + lua_writestring(s, l); + lua_pop(L, 1); /* pop result */ + } + lua_writeline(); + return 0; +} + + +#define SPACECHARS " \f\n\r\t\v" + +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle signal */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + +static int luaB_tonumber (lua_State *L) { + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ + luaL_checkany(L, 1); + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + } + } + else { + size_t l; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; + } /* else not a number */ + } /* else not a number */ + lua_pushnil(L); /* not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + int level = (int)luaL_optinteger(L, 2, 1); + lua_settop(L, 1); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); +} + + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ +} + + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) + return luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; +} + + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; +} + + +static int luaB_rawlen (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string expected"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; +} + + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; +} + + +static int luaB_collectgarbage (lua_State *L) { + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", + "isrunning", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; + int ex = (int)luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, ex); + switch (o) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: case LUA_GCISRUNNING: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushinteger(L, res); + return 1; + } + } +} + + +static int luaB_type (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); + return 1; +} + + +static int pairsmeta (lua_State *L, const char *method, int iszero, + lua_CFunction iter) { + luaL_checkany(L, 1); + if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ + lua_pushcfunction(L, iter); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int luaB_pairs (lua_State *L) { + return pairsmeta(L, "__pairs", 0, luaB_next); +} + + +/* +** Traversal function for 'ipairs' +*/ +static int ipairsaux (lua_State *L) { + lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +} + + +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ +static int luaB_ipairs (lua_State *L) { +#if defined(LUA_COMPAT_IPAIRS) + return pairsmeta(L, "__ipairs", 1, ipairsaux); +#else + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +#endif +} + + +static int load_aux (lua_State *L, int status, int envidx) { + if (status == LUA_OK) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } + return 1; + } + else { /* error (message is on top of the stack) */ + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + const char *mode = luaL_optstring(L, 2, NULL); + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ + int status = luaL_loadfilex(L, fname, mode); + return load_aux(L, status, env); +} + + +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + + +/* +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). +*/ +#define RESERVEDSLOT 5 + + +/* +** Reader for generic 'load' function: 'lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)(ud); /* not used */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ + *size = 0; + return NULL; + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "reader function must return a string"); + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); +} + + +static int luaB_load (lua_State *L) { + int status; + size_t l; + const char *s = lua_tolstring(L, 1, &l); + const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, 2, s); + status = luaL_loadbufferx(L, s, l, chunkname, mode); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, NULL, chunkname, mode); + } + return load_aux(L, status, env); +} + +/* }====================================================== */ + + +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ + return lua_gettop(L) - 1; +} + + +static int luaB_dofile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + lua_settop(L, 1); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L, 0, 0); +} + + +static int luaB_assert (lua_State *L) { + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } +} + + +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + lua_Integer i = luaL_checkinteger(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - (int)i; + } +} + + +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (status != LUA_OK && status != LUA_YIELD) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ + return 2; /* return false, msg */ + } + else + return lua_gettop(L) - (int)extra; /* return all results */ +} + + +static int luaB_pcall (lua_State *L) { + int status; + luaL_checkany(L, 1); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); +} + + +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have ; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ +static int luaB_xpcall (lua_State *L) { + int status; + int n = lua_gettop(L); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); +} + + +static int luaB_tostring (lua_State *L) { + luaL_checkany(L, 1); + luaL_tolstring(L, 1, NULL); + return 1; +} + + +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, + {"error", luaB_error}, + {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, +#if defined(LUA_COMPAT_LOADSTRING) + {"loadstring", luaB_load}, +#endif + {"next", luaB_next}, + {"pairs", luaB_pairs}, + {"pcall", luaB_pcall}, + {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setmetatable", luaB_setmetatable}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + {"xpcall", luaB_xpcall}, + /* placeholders */ + {"_G", NULL}, + {"_VERSION", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_base (lua_State *L) { + /* open lib into global table */ + lua_pushglobaltable(L); + luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_G"); + /* set global _VERSION */ + lua_pushliteral(L, LUA_VERSION); + lua_setfield(L, -2, "_VERSION"); + return 1; +} + diff --git a/libs/lua/source/lbitlib.c b/libs/lua/source/lbitlib.c index 4786c0d4..04509d83 100644 --- a/libs/lua/source/lbitlib.c +++ b/libs/lua/source/lbitlib.c @@ -1,233 +1,233 @@ -/* -** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ -** Standard library for bitwise operations -** See Copyright Notice in lua.h -*/ - -#define lbitlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if defined(LUA_COMPAT_BITLIB) /* { */ - - -#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) - - -/* number of bits to consider in a number */ -#if !defined(LUA_NBITS) -#define LUA_NBITS 32 -#endif - - -/* -** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must -** be made in two parts to avoid problems when LUA_NBITS is equal to the -** number of bits in a lua_Unsigned.) -*/ -#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) - - -/* macro to trim extra bits */ -#define trim(x) ((x) & ALLONES) - - -/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ -#define mask(n) (~((ALLONES << 1) << ((n) - 1))) - - - -static lua_Unsigned andaux (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = ~(lua_Unsigned)0; - for (i = 1; i <= n; i++) - r &= checkunsigned(L, i); - return trim(r); -} - - -static int b_and (lua_State *L) { - lua_Unsigned r = andaux(L); - pushunsigned(L, r); - return 1; -} - - -static int b_test (lua_State *L) { - lua_Unsigned r = andaux(L); - lua_pushboolean(L, r != 0); - return 1; -} - - -static int b_or (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r |= checkunsigned(L, i); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_xor (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r ^= checkunsigned(L, i); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_not (lua_State *L) { - lua_Unsigned r = ~checkunsigned(L, 1); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { - if (i < 0) { /* shift right? */ - i = -i; - r = trim(r); - if (i >= LUA_NBITS) r = 0; - else r >>= i; - } - else { /* shift left */ - if (i >= LUA_NBITS) r = 0; - else r <<= i; - r = trim(r); - } - pushunsigned(L, r); - return 1; -} - - -static int b_lshift (lua_State *L) { - return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); -} - - -static int b_rshift (lua_State *L) { - return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); -} - - -static int b_arshift (lua_State *L) { - lua_Unsigned r = checkunsigned(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); - if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) - return b_shift(L, r, -i); - else { /* arithmetic shift for 'negative' number */ - if (i >= LUA_NBITS) r = ALLONES; - else - r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ - pushunsigned(L, r); - return 1; - } -} - - -static int b_rot (lua_State *L, lua_Integer d) { - lua_Unsigned r = checkunsigned(L, 1); - int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ - r = trim(r); - if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ - r = (r << i) | (r >> (LUA_NBITS - i)); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_lrot (lua_State *L) { - return b_rot(L, luaL_checkinteger(L, 2)); -} - - -static int b_rrot (lua_State *L) { - return b_rot(L, -luaL_checkinteger(L, 2)); -} - - -/* -** get field and width arguments for field-manipulation functions, -** checking whether they are valid. -** ('luaL_error' called without 'return' to avoid later warnings about -** 'width' being used uninitialized.) -*/ -static int fieldargs (lua_State *L, int farg, int *width) { - lua_Integer f = luaL_checkinteger(L, farg); - lua_Integer w = luaL_optinteger(L, farg + 1, 1); - luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); - luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); - if (f + w > LUA_NBITS) - luaL_error(L, "trying to access non-existent bits"); - *width = (int)w; - return (int)f; -} - - -static int b_extract (lua_State *L) { - int w; - lua_Unsigned r = trim(checkunsigned(L, 1)); - int f = fieldargs(L, 2, &w); - r = (r >> f) & mask(w); - pushunsigned(L, r); - return 1; -} - - -static int b_replace (lua_State *L) { - int w; - lua_Unsigned r = trim(checkunsigned(L, 1)); - lua_Unsigned v = trim(checkunsigned(L, 2)); - int f = fieldargs(L, 3, &w); - lua_Unsigned m = mask(w); - r = (r & ~(m << f)) | ((v & m) << f); - pushunsigned(L, r); - return 1; -} - - -static const luaL_Reg bitlib[] = { - {"arshift", b_arshift}, - {"band", b_and}, - {"bnot", b_not}, - {"bor", b_or}, - {"bxor", b_xor}, - {"btest", b_test}, - {"extract", b_extract}, - {"lrotate", b_lrot}, - {"lshift", b_lshift}, - {"replace", b_replace}, - {"rrotate", b_rrot}, - {"rshift", b_rshift}, - {NULL, NULL} -}; - - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - luaL_newlib(L, bitlib); - return 1; -} - - -#else /* }{ */ - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - return luaL_error(L, "library 'bit32' has been deprecated"); -} - -#endif /* } */ +/* +** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ +** Standard library for bitwise operations +** See Copyright Notice in lua.h +*/ + +#define lbitlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#if defined(LUA_COMPAT_BITLIB) /* { */ + + +#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) + + +/* number of bits to consider in a number */ +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif + + +/* +** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must +** be made in two parts to avoid problems when LUA_NBITS is equal to the +** number of bits in a lua_Unsigned.) +*/ +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + + +/* macro to trim extra bits */ +#define trim(x) ((x) & ALLONES) + + +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + + + +static lua_Unsigned andaux (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = ~(lua_Unsigned)0; + for (i = 1; i <= n; i++) + r &= checkunsigned(L, i); + return trim(r); +} + + +static int b_and (lua_State *L) { + lua_Unsigned r = andaux(L); + pushunsigned(L, r); + return 1; +} + + +static int b_test (lua_State *L) { + lua_Unsigned r = andaux(L); + lua_pushboolean(L, r != 0); + return 1; +} + + +static int b_or (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r |= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_xor (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r ^= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_not (lua_State *L) { + lua_Unsigned r = ~checkunsigned(L, 1); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { + if (i < 0) { /* shift right? */ + i = -i; + r = trim(r); + if (i >= LUA_NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= LUA_NBITS) r = 0; + else r <<= i; + r = trim(r); + } + pushunsigned(L, r); + return 1; +} + + +static int b_lshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); +} + + +static int b_arshift (lua_State *L) { + lua_Unsigned r = checkunsigned(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= LUA_NBITS) r = ALLONES; + else + r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ + pushunsigned(L, r); + return 1; + } +} + + +static int b_rot (lua_State *L, lua_Integer d) { + lua_Unsigned r = checkunsigned(L, 1); + int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ + r = trim(r); + if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ + r = (r << i) | (r >> (LUA_NBITS - i)); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_lrot (lua_State *L) { + return b_rot(L, luaL_checkinteger(L, 2)); +} + + +static int b_rrot (lua_State *L) { + return b_rot(L, -luaL_checkinteger(L, 2)); +} + + +/* +** get field and width arguments for field-manipulation functions, +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) +*/ +static int fieldargs (lua_State *L, int farg, int *width) { + lua_Integer f = luaL_checkinteger(L, farg); + lua_Integer w = luaL_optinteger(L, farg + 1, 1); + luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); + luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); + if (f + w > LUA_NBITS) + luaL_error(L, "trying to access non-existent bits"); + *width = (int)w; + return (int)f; +} + + +static int b_extract (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + int f = fieldargs(L, 2, &w); + r = (r >> f) & mask(w); + pushunsigned(L, r); + return 1; +} + + +static int b_replace (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + lua_Unsigned v = trim(checkunsigned(L, 2)); + int f = fieldargs(L, 3, &w); + lua_Unsigned m = mask(w); + r = (r & ~(m << f)) | ((v & m) << f); + pushunsigned(L, r); + return 1; +} + + +static const luaL_Reg bitlib[] = { + {"arshift", b_arshift}, + {"band", b_and}, + {"bnot", b_not}, + {"bor", b_or}, + {"bxor", b_xor}, + {"btest", b_test}, + {"extract", b_extract}, + {"lrotate", b_lrot}, + {"lshift", b_lshift}, + {"replace", b_replace}, + {"rrotate", b_rrot}, + {"rshift", b_rshift}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + luaL_newlib(L, bitlib); + return 1; +} + + +#else /* }{ */ + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + return luaL_error(L, "library 'bit32' has been deprecated"); +} + +#endif /* } */ diff --git a/libs/lua/source/lcode.c b/libs/lua/source/lcode.c index 12619f54..eb833fc3 100644 --- a/libs/lua/source/lcode.c +++ b/libs/lua/source/lcode.c @@ -1,1203 +1,1203 @@ -/* -** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - -#define lcode_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "llex.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstring.h" -#include "ltable.h" -#include "lvm.h" - - -/* Maximum number of registers in a Lua function (must fit in 8 bits) */ -#define MAXREGS 255 - - -#define hasjumps(e) ((e)->t != (e)->f) - - -/* -** If expression is a numeric constant, fills 'v' with its value -** and returns 1. Otherwise, returns 0. -*/ -static int tonumeral(const expdesc *e, TValue *v) { - if (hasjumps(e)) - return 0; /* not a numeral */ - switch (e->k) { - case VKINT: - if (v) setivalue(v, e->u.ival); - return 1; - case VKFLT: - if (v) setfltvalue(v, e->u.nval); - return 1; - default: return 0; - } -} - - -/* -** Create a OP_LOADNIL instruction, but try to optimize: if the previous -** instruction is also OP_LOADNIL and ranges are compatible, adjust -** range of previous instruction instead of emitting a new one. (For -** instance, 'local a; local b' will generate a single opcode.) -*/ -void luaK_nil (FuncState *fs, int from, int n) { - Instruction *previous; - int l = from + n - 1; /* last register to set nil */ - if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ - int pfrom = GETARG_A(*previous); /* get previous range */ - int pl = pfrom + GETARG_B(*previous); - if ((pfrom <= from && from <= pl + 1) || - (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ - if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ - if (pl > l) l = pl; /* l = max(l, pl) */ - SETARG_A(*previous, from); - SETARG_B(*previous, l - from); - return; - } - } /* else go through */ - } - luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ -} - - -/* -** Gets the destination address of a jump instruction. Used to traverse -** a list of jumps. -*/ -static int getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - - -/* -** Fix jump instruction at position 'pc' to jump to 'dest'. -** (Jump addresses are relative in Lua) -*/ -static void fixjump (FuncState *fs, int pc, int dest) { - Instruction *jmp = &fs->f->code[pc]; - int offset = dest - (pc + 1); - lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); -} - - -/* -** Concatenate jump-list 'l2' into jump-list 'l1' -*/ -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (l2 == NO_JUMP) return; /* nothing to concatenate? */ - else if (*l1 == NO_JUMP) /* no original list? */ - *l1 = l2; /* 'l1' points to 'l2' */ - else { - int list = *l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); /* last element links to 'l2' */ - } -} - - -/* -** Create a jump instruction and return its position, so its destination -** can be fixed later (with 'fixjump'). If there are jumps to -** this position (kept in 'jpc'), link them all together so that -** 'patchlistaux' will fix all them directly to the final destination. -*/ -int luaK_jump (FuncState *fs) { - int jpc = fs->jpc; /* save list of jumps to here */ - int j; - fs->jpc = NO_JUMP; /* no more jumps to here */ - j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); - luaK_concat(fs, &j, jpc); /* keep them on hold */ - return j; -} - - -/* -** Code a 'return' instruction -*/ -void luaK_ret (FuncState *fs, int first, int nret) { - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - - -/* -** Code a "conditional jump", that is, a test or comparison opcode -** followed by a jump. Return jump position. -*/ -static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); - return luaK_jump(fs); -} - - -/* -** returns current 'pc' and marks it as a jump target (to avoid wrong -** optimizations with consecutive instructions not in the same basic block). -*/ -int luaK_getlabel (FuncState *fs) { - fs->lasttarget = fs->pc; - return fs->pc; -} - - -/* -** Returns the position of the instruction "controlling" a given -** jump (that is, its condition), or the jump itself if it is -** unconditional. -*/ -static Instruction *getjumpcontrol (FuncState *fs, int pc) { - Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) - return pi-1; - else - return pi; -} - - -/* -** Patch destination register for a TESTSET instruction. -** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). -** Otherwise, if 'reg' is not 'NO_REG', set it as the destination -** register. Otherwise, change instruction to a simple 'TEST' (produces -** no register value) -*/ -static int patchtestreg (FuncState *fs, int node, int reg) { - Instruction *i = getjumpcontrol(fs, node); - if (GET_OPCODE(*i) != OP_TESTSET) - return 0; /* cannot patch other instructions */ - if (reg != NO_REG && reg != GETARG_B(*i)) - SETARG_A(*i, reg); - else { - /* no register to put value or register already has the value; - change instruction to simple test */ - *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); - } - return 1; -} - - -/* -** Traverse a list of tests ensuring no one produces a value -*/ -static void removevalues (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) - patchtestreg(fs, list, NO_REG); -} - - -/* -** Traverse a list of tests, patching their destination address and -** registers: tests producing values jump to 'vtarget' (and put their -** values in 'reg'), other tests jump to 'dtarget'. -*/ -static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, - int dtarget) { - while (list != NO_JUMP) { - int next = getjump(fs, list); - if (patchtestreg(fs, list, reg)) - fixjump(fs, list, vtarget); - else - fixjump(fs, list, dtarget); /* jump to default target */ - list = next; - } -} - - -/* -** Ensure all pending jumps to current position are fixed (jumping -** to current position with no values) and reset list of pending -** jumps -*/ -static void dischargejpc (FuncState *fs) { - patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); - fs->jpc = NO_JUMP; -} - - -/* -** Add elements in 'list' to list of pending jumps to "here" -** (current position) -*/ -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); /* mark "here" as a jump target */ - luaK_concat(fs, &fs->jpc, list); -} - - -/* -** Path all jumps in 'list' to jump to 'target'. -** (The assert means that we cannot fix a jump to a forward address -** because we only know addresses once code is generated.) -*/ -void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) /* 'target' is current position? */ - luaK_patchtohere(fs, list); /* add list to pending jumps */ - else { - lua_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target); - } -} - - -/* -** Path all jumps in 'list' to close upvalues up to given 'level' -** (The assertion checks that jumps either were closing nothing -** or were closing higher levels, from inner blocks.) -*/ -void luaK_patchclose (FuncState *fs, int list, int level) { - level++; /* argument is +1 to reserve 0 as non-op */ - for (; list != NO_JUMP; list = getjump(fs, list)) { - lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && - (GETARG_A(fs->f->code[list]) == 0 || - GETARG_A(fs->f->code[list]) >= level)); - SETARG_A(fs->f->code[list], level); - } -} - - -/* -** Emit instruction 'i', checking for array sizes and saving also its -** line information. Return 'i' position. -*/ -static int luaK_code (FuncState *fs, Instruction i) { - Proto *f = fs->f; - dischargejpc(fs); /* 'pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "opcodes"); - f->code[fs->pc] = i; - /* save corresponding line information */ - luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "opcodes"); - f->lineinfo[fs->pc] = fs->ls->lastline; - return fs->pc++; -} - - -/* -** Format and emit an 'iABC' instruction. (Assertions check consistency -** of parameters versus opcode.) -*/ -int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == iABC); - lua_assert(getBMode(o) != OpArgN || b == 0); - lua_assert(getCMode(o) != OpArgN || c == 0); - lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); - return luaK_code(fs, CREATE_ABC(o, a, b, c)); -} - - -/* -** Format and emit an 'iABx' instruction. -*/ -int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { - lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - lua_assert(getCMode(o) == OpArgN); - lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); - return luaK_code(fs, CREATE_ABx(o, a, bc)); -} - - -/* -** Emit an "extra argument" instruction (format 'iAx') -*/ -static int codeextraarg (FuncState *fs, int a) { - lua_assert(a <= MAXARG_Ax); - return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); -} - - -/* -** Emit a "load constant" instruction, using either 'OP_LOADK' -** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' -** instruction with "extra argument". -*/ -int luaK_codek (FuncState *fs, int reg, int k) { - if (k <= MAXARG_Bx) - return luaK_codeABx(fs, OP_LOADK, reg, k); - else { - int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); - codeextraarg(fs, k); - return p; - } -} - - -/* -** Check register-stack level, keeping track of its maximum size -** in field 'maxstacksize' -*/ -void luaK_checkstack (FuncState *fs, int n) { - int newstack = fs->freereg + n; - if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXREGS) - luaX_syntaxerror(fs->ls, - "function or expression needs too many registers"); - fs->f->maxstacksize = cast_byte(newstack); - } -} - - -/* -** Reserve 'n' registers in register stack -*/ -void luaK_reserveregs (FuncState *fs, int n) { - luaK_checkstack(fs, n); - fs->freereg += n; -} - - -/* -** Free register 'reg', if it is neither a constant index nor -** a local variable. -) -*/ -static void freereg (FuncState *fs, int reg) { - if (!ISK(reg) && reg >= fs->nactvar) { - fs->freereg--; - lua_assert(reg == fs->freereg); - } -} - - -/* -** Free register used by expression 'e' (if any) -*/ -static void freeexp (FuncState *fs, expdesc *e) { - if (e->k == VNONRELOC) - freereg(fs, e->u.info); -} - - -/* -** Free registers used by expressions 'e1' and 'e2' (if any) in proper -** order. -*/ -static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { - int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; - int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; - if (r1 > r2) { - freereg(fs, r1); - freereg(fs, r2); - } - else { - freereg(fs, r2); - freereg(fs, r1); - } -} - - -/* -** Add constant 'v' to prototype's list of constants (field 'k'). -** Use scanner's table to cache position of constants in constant list -** and try to reuse constants. Because some values should not be used -** as keys (nil cannot be a key, integer keys can collapse with float -** keys), the caller must provide a useful 'key' for indexing the cache. -*/ -static int addk (FuncState *fs, TValue *key, TValue *v) { - lua_State *L = fs->ls->L; - Proto *f = fs->f; - TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ - int k, oldsize; - if (ttisinteger(idx)) { /* is there an index there? */ - k = cast_int(ivalue(idx)); - /* correct value? (warning: must distinguish floats from integers!) */ - if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && - luaV_rawequalobj(&f->k[k], v)) - return k; /* reuse index */ - } - /* constant not found; create a new entry */ - oldsize = f->sizek; - k = fs->nk; - /* numerical value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setivalue(idx, k); - luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); - while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); - setobj(L, &f->k[k], v); - fs->nk++; - luaC_barrier(L, f, v); - return k; -} - - -/* -** Add a string to list of constants and return its index. -*/ -int luaK_stringK (FuncState *fs, TString *s) { - TValue o; - setsvalue(fs->ls->L, &o, s); - return addk(fs, &o, &o); /* use string itself as key */ -} - - -/* -** Add an integer to list of constants and return its index. -** Integers use userdata as keys to avoid collision with floats with -** same value; conversion to 'void*' is used only for hashing, so there -** are no "precision" problems. -*/ -int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast(void*, cast(size_t, n))); - setivalue(&o, n); - return addk(fs, &k, &o); -} - -/* -** Add a float to list of constants and return its index. -*/ -static int luaK_numberK (FuncState *fs, lua_Number r) { - TValue o; - setfltvalue(&o, r); - return addk(fs, &o, &o); /* use number itself as key */ -} - - -/* -** Add a boolean to list of constants and return its index. -*/ -static int boolK (FuncState *fs, int b) { - TValue o; - setbvalue(&o, b); - return addk(fs, &o, &o); /* use boolean itself as key */ -} - - -/* -** Add nil to list of constants and return its index. -*/ -static int nilK (FuncState *fs) { - TValue k, v; - setnilvalue(&v); - /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs->ls->L, &k, fs->ls->h); - return addk(fs, &k, &v); -} - - -/* -** Fix an expression to return the number of results 'nresults'. -** Either 'e' is a multi-ret expression (function call or vararg) -** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). -*/ -void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { - if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getinstruction(fs, e), nresults + 1); - } - else if (e->k == VVARARG) { - Instruction *pc = &getinstruction(fs, e); - SETARG_B(*pc, nresults + 1); - SETARG_A(*pc, fs->freereg); - luaK_reserveregs(fs, 1); - } - else lua_assert(nresults == LUA_MULTRET); -} - - -/* -** Fix an expression to return one result. -** If expression is not a multi-ret expression (function call or -** vararg), it already returns one result, so nothing needs to be done. -** Function calls become VNONRELOC expressions (as its result comes -** fixed in the base register of the call), while vararg expressions -** become VRELOCABLE (as OP_VARARG puts its results where it wants). -** (Calls are created returning one result, so that does not need -** to be fixed.) -*/ -void luaK_setoneret (FuncState *fs, expdesc *e) { - if (e->k == VCALL) { /* expression is an open function call? */ - /* already returns 1 value */ - lua_assert(GETARG_C(getinstruction(fs, e)) == 2); - e->k = VNONRELOC; /* result has fixed position */ - e->u.info = GETARG_A(getinstruction(fs, e)); - } - else if (e->k == VVARARG) { - SETARG_B(getinstruction(fs, e), 2); - e->k = VRELOCABLE; /* can relocate its simple result */ - } -} - - -/* -** Ensure that expression 'e' is not a variable. -*/ -void luaK_dischargevars (FuncState *fs, expdesc *e) { - switch (e->k) { - case VLOCAL: { /* already in a register */ - e->k = VNONRELOC; /* becomes a non-relocatable value */ - break; - } - case VUPVAL: { /* move value to some (pending) register */ - e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - case VINDEXED: { - OpCode op; - freereg(fs, e->u.ind.idx); - if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ - freereg(fs, e->u.ind.t); - op = OP_GETTABLE; - } - else { - lua_assert(e->u.ind.vt == VUPVAL); - op = OP_GETTABUP; /* 't' is in an upvalue */ - } - e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; - break; - } - case VVARARG: case VCALL: { - luaK_setoneret(fs, e); - break; - } - default: break; /* there is one value available (somewhere) */ - } -} - - -/* -** Ensures expression value is in register 'reg' (and therefore -** 'e' will become a non-relocatable expression). -*/ -static void discharge2reg (FuncState *fs, expdesc *e, int reg) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: { - luaK_nil(fs, reg, 1); - break; - } - case VFALSE: case VTRUE: { - luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); - break; - } - case VK: { - luaK_codek(fs, reg, e->u.info); - break; - } - case VKFLT: { - luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); - break; - } - case VKINT: { - luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); - break; - } - case VRELOCABLE: { - Instruction *pc = &getinstruction(fs, e); - SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ - break; - } - case VNONRELOC: { - if (reg != e->u.info) - luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); - break; - } - default: { - lua_assert(e->k == VJMP); - return; /* nothing to do... */ - } - } - e->u.info = reg; - e->k = VNONRELOC; -} - - -/* -** Ensures expression value is in any register. -*/ -static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { /* no fixed register yet? */ - luaK_reserveregs(fs, 1); /* get a register */ - discharge2reg(fs, e, fs->freereg-1); /* put value there */ - } -} - - -static int code_loadbool (FuncState *fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); -} - - -/* -** check whether list has any jump that do not produce a value -** or produce an inverted value -*/ -static int need_value (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) return 1; - } - return 0; /* not found */ -} - - -/* -** Ensures final expression result (including results from its jump -** lists) is in register 'reg'. -** If expression has jumps, need to patch these jumps either to -** its final position or to "load" instructions (for those tests -** that do not produce values). -*/ -static void exp2reg (FuncState *fs, expdesc *e, int reg) { - discharge2reg(fs, e, reg); - if (e->k == VJMP) /* expression itself is a test? */ - luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ - if (hasjumps(e)) { - int final; /* position after whole expression */ - int p_f = NO_JUMP; /* position of an eventual LOAD false */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t) || need_value(fs, e->f)) { - int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_loadbool(fs, reg, 0, 1); - p_t = code_loadbool(fs, reg, 1, 0); - luaK_patchtohere(fs, fj); - } - final = luaK_getlabel(fs); - patchlistaux(fs, e->f, final, reg, p_f); - patchlistaux(fs, e->t, final, reg, p_t); - } - e->f = e->t = NO_JUMP; - e->u.info = reg; - e->k = VNONRELOC; -} - - -/* -** Ensures final expression result (including results from its jump -** lists) is in next available register. -*/ -void luaK_exp2nextreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - freeexp(fs, e); - luaK_reserveregs(fs, 1); - exp2reg(fs, e, fs->freereg - 1); -} - - -/* -** Ensures final expression result (including results from its jump -** lists) is in some (any) register and return that register. -*/ -int luaK_exp2anyreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - if (e->k == VNONRELOC) { /* expression already has a register? */ - if (!hasjumps(e)) /* no jumps? */ - return e->u.info; /* result is already in a register */ - if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.info); /* put final result in it */ - return e->u.info; - } - } - luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ - return e->u.info; -} - - -/* -** Ensures final expression result is either in a register or in an -** upvalue. -*/ -void luaK_exp2anyregup (FuncState *fs, expdesc *e) { - if (e->k != VUPVAL || hasjumps(e)) - luaK_exp2anyreg(fs, e); -} - - -/* -** Ensures final expression result is either in a register or it is -** a constant. -*/ -void luaK_exp2val (FuncState *fs, expdesc *e) { - if (hasjumps(e)) - luaK_exp2anyreg(fs, e); - else - luaK_dischargevars(fs, e); -} - - -/* -** Ensures final expression result is in a valid R/K index -** (that is, it is either in a register or in 'k' with an index -** in the range of R/K indices). -** Returns R/K index. -*/ -int luaK_exp2RK (FuncState *fs, expdesc *e) { - luaK_exp2val(fs, e); - switch (e->k) { /* move constants to 'k' */ - case VTRUE: e->u.info = boolK(fs, 1); goto vk; - case VFALSE: e->u.info = boolK(fs, 0); goto vk; - case VNIL: e->u.info = nilK(fs); goto vk; - case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; - case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; - case VK: - vk: - e->k = VK; - if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ - return RKASK(e->u.info); - else break; - default: break; - } - /* not a constant in the right range: put it in a register */ - return luaK_exp2anyreg(fs, e); -} - - -/* -** Generate code to store result of expression 'ex' into variable 'var'. -*/ -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { - switch (var->k) { - case VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ - return; - } - case VUPVAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); - break; - } - case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; - int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); - break; - } - default: lua_assert(0); /* invalid var kind to store */ - } - freeexp(fs, ex); -} - - -/* -** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). -*/ -void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int ereg; - luaK_exp2anyreg(fs, e); - ereg = e->u.info; /* register where 'e' was placed */ - freeexp(fs, e); - e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; /* self expression has a fixed register */ - luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ - luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); - freeexp(fs, key); -} - - -/* -** Negate condition 'e' (where 'e' is a comparison). -*/ -static void negatecondition (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->u.info); - lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && - GET_OPCODE(*pc) != OP_TEST); - SETARG_A(*pc, !(GETARG_A(*pc))); -} - - -/* -** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' -** is true, code will jump if 'e' is true.) Return jump position. -** Optimize when 'e' is 'not' something, inverting the condition -** and removing the 'not'. -*/ -static int jumponcond (FuncState *fs, expdesc *e, int cond) { - if (e->k == VRELOCABLE) { - Instruction ie = getinstruction(fs, e); - if (GET_OPCODE(ie) == OP_NOT) { - fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); -} - - -/* -** Emit code to go through if 'e' is true, jump otherwise. -*/ -void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of new jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { /* condition? */ - negatecondition(fs, e); /* jump when it is false */ - pc = e->u.info; /* save jump position */ - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 0); /* jump when false */ - break; - } - } - luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ - luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ - e->t = NO_JUMP; -} - - -/* -** Emit code to go through if 'e' is false, jump otherwise. -*/ -void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of new jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VJMP: { - pc = e->u.info; /* already jump if true */ - break; - } - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - default: { - pc = jumponcond(fs, e, 1); /* jump if true */ - break; - } - } - luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ - luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ - e->f = NO_JUMP; -} - - -/* -** Code 'not e', doing constant folding. -*/ -static void codenot (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - e->k = VTRUE; /* true == not nil == not false */ - break; - } - case VK: case VKFLT: case VKINT: case VTRUE: { - e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ - break; - } - case VJMP: { - negatecondition(fs, e); - break; - } - case VRELOCABLE: - case VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - default: lua_assert(0); /* cannot happen */ - } - /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); /* values are useless when negated */ - removevalues(fs, e->t); -} - - -/* -** Create expression 't[k]'. 't' must have its final result already in a -** register or upvalue. -*/ -void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); - t->u.ind.t = t->u.info; /* register or upvalue index */ - t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ - t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; - t->k = VINDEXED; -} - - -/* -** Return false if folding can raise an error. -** Bitwise operations need operands convertible to integers; division -** operations cannot have 0 as divisor. -*/ -static int validop (int op, TValue *v1, TValue *v2) { - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ - lua_Integer i; - return (tointeger(v1, &i) && tointeger(v2, &i)); - } - case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ - return (nvalue(v2) != 0); - default: return 1; /* everything else is valid */ - } -} - - -/* -** Try to "constant-fold" an operation; return 1 iff successful. -** (In this case, 'e1' has the final result.) -*/ -static int constfolding (FuncState *fs, int op, expdesc *e1, - const expdesc *e2) { - TValue v1, v2, res; - if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) - return 0; /* non-numeric operands or not safe to fold */ - luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ - if (ttisinteger(&res)) { - e1->k = VKINT; - e1->u.ival = ivalue(&res); - } - else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ - lua_Number n = fltvalue(&res); - if (luai_numisnan(n) || n == 0) - return 0; - e1->k = VKFLT; - e1->u.nval = n; - } - return 1; -} - - -/* -** Emit code for unary expressions that "produce values" -** (everything but 'not'). -** Expression to produce final result will be encoded in 'e'. -*/ -static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { - int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ - freeexp(fs, e); - e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ - e->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); -} - - -/* -** Emit code for binary expressions that "produce values" -** (everything but logical operators 'and'/'or' and comparison -** operators). -** Expression to produce final result will be encoded in 'e1'. -** Because 'luaK_exp2RK' can free registers, its calls must be -** in "stack order" (that is, first on 'e2', which may have more -** recent registers to be released). -*/ -static void codebinexpval (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ - int rk1 = luaK_exp2RK(fs, e1); - freeexps(fs, e1, e2); - e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); -} - - -/* -** Emit code for comparisons. -** 'e1' was already put in R/K form by 'luaK_infix'. -*/ -static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { - int rk1 = (e1->k == VK) ? RKASK(e1->u.info) - : check_exp(e1->k == VNONRELOC, e1->u.info); - int rk2 = luaK_exp2RK(fs, e2); - freeexps(fs, e1, e2); - switch (opr) { - case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ - e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); - break; - } - case OPR_GT: case OPR_GE: { - /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ - OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); - e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ - break; - } - default: { /* '==', '<', '<=' use their own opcodes */ - OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); - e1->u.info = condjump(fs, op, 1, rk1, rk2); - break; - } - } - e1->k = VJMP; -} - - -/* -** Aplly prefix operation 'op' to expression 'e'. -*/ -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { - static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; - switch (op) { - case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ - if (constfolding(fs, op + LUA_OPUNM, e, &ef)) - break; - /* FALLTHROUGH */ - case OPR_LEN: - codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); - break; - case OPR_NOT: codenot(fs, e); break; - default: lua_assert(0); - } -} - - -/* -** Process 1st operand 'v' of binary operation 'op' before reading -** 2nd operand. -*/ -void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { - switch (op) { - case OPR_AND: { - luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ - break; - } - case OPR_OR: { - luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ - break; - } - case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ - break; - } - case OPR_ADD: case OPR_SUB: - case OPR_MUL: case OPR_DIV: case OPR_IDIV: - case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!tonumeral(v, NULL)) - luaK_exp2RK(fs, v); - /* else keep numeral, which may be folded with 2nd operand */ - break; - } - default: { - luaK_exp2RK(fs, v); - break; - } - } -} - - -/* -** Finalize code for binary operation, after reading 2nd operand. -** For '(a .. b .. c)' (which is '(a .. (b .. c))', because -** concatenation is right associative), merge second CONCAT into first -** one. -*/ -void luaK_posfix (FuncState *fs, BinOpr op, - expdesc *e1, expdesc *e2, int line) { - switch (op) { - case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e2->f, e1->f); - *e1 = *e2; - break; - } - case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e2->t, e1->t); - *e1 = *e2; - break; - } - case OPR_CONCAT: { - luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && - GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); - freeexp(fs, e1); - SETARG_B(getinstruction(fs, e2), e1->u.info); - e1->k = VRELOCABLE; e1->u.info = e2->u.info; - } - else { - luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codebinexpval(fs, OP_CONCAT, e1, e2, line); - } - break; - } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_IDIV: case OPR_MOD: case OPR_POW: - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: - case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, op, e1, e2); - break; - } - default: lua_assert(0); - } -} - - -/* -** Change line information associated with current position. -*/ -void luaK_fixline (FuncState *fs, int line) { - fs->f->lineinfo[fs->pc - 1] = line; -} - - -/* -** Emit a SETLIST instruction. -** 'base' is register that keeps table; -** 'nelems' is #table plus those to be stored now; -** 'tostore' is number of values (in registers 'base + 1',...) to add to -** table (or LUA_MULTRET to add up to stack top). -*/ -void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == LUA_MULTRET) ? 0 : tostore; - lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); - if (c <= MAXARG_C) - luaK_codeABC(fs, OP_SETLIST, base, b, c); - else if (c <= MAXARG_Ax) { - luaK_codeABC(fs, OP_SETLIST, base, b, 0); - codeextraarg(fs, c); - } - else - luaX_syntaxerror(fs->ls, "constructor too long"); - fs->freereg = base + 1; /* free registers with list values */ -} - +/* +** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#define lcode_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + +#define hasjumps(e) ((e)->t != (e)->f) + + +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +static int tonumeral(const expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } +} + + +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ +void luaK_nil (FuncState *fs, int from, int n) { + Instruction *previous; + int l = from + n - 1; /* last register to set nil */ + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); + return; + } + } /* else go through */ + } + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ +} + + +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). If there are jumps to +** this position (kept in 'jpc'), link them all together so that +** 'patchlistaux' will fix all them directly to the final destination. +*/ +int luaK_jump (FuncState *fs) { + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; /* no more jumps to here */ + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ + return j; +} + + +/* +** Code a 'return' instruction +*/ +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); +} + + +/* +** returns current 'pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; +} + + +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) + return pi-1; + else + return pi; +} + + +/* +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) +*/ +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) + SETARG_A(*i, reg); + else { + /* no register to put value or register already has the value; + change instruction to simple test */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + } + return 1; +} + + +/* +** Traverse a list of tests ensuring no one produces a value +*/ +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); +} + + +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg)) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } +} + + +/* +** Ensure all pending jumps to current position are fixed (jumping +** to current position with no values) and reset list of pending +** jumps +*/ +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; +} + + +/* +** Add elements in 'list' to list of pending jumps to "here" +** (current position) +*/ +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_concat(fs, &fs->jpc, list); +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) /* 'target' is current position? */ + luaK_patchtohere(fs, list); /* add list to pending jumps */ + else { + lua_assert(target < fs->pc); + patchlistaux(fs, list, target, NO_REG, target); + } +} + + +/* +** Path all jumps in 'list' to close upvalues up to given 'level' +** (The assertion checks that jumps either were closing nothing +** or were closing higher levels, from inner blocks.) +*/ +void luaK_patchclose (FuncState *fs, int list, int level) { + level++; /* argument is +1 to reserve 0 as non-op */ + for (; list != NO_JUMP; list = getjump(fs, list)) { + lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && + (GETARG_A(fs->f->code[list]) == 0 || + GETARG_A(fs->f->code[list]) >= level)); + SETARG_A(fs->f->code[list], level); + } +} + + +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ +static int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + dischargejpc(fs); /* 'pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; +} + + +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return luaK_code(fs, CREATE_ABC(o, a, b, c)); +} + + +/* +** Format and emit an 'iABx' instruction. +*/ +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ +int luaK_codek (FuncState *fs, int reg, int k) { + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); + else { + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); + fs->f->maxstacksize = cast_byte(newstack); + } +} + + +/* +** Reserve 'n' registers in register stack +*/ +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; +} + + +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ +static void freereg (FuncState *fs, int reg) { + if (!ISK(reg) && reg >= fs->nactvar) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } +} + + +/* +** Free register used by expression 'e' (if any) +*/ +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.info); +} + + +/* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +*/ +static int addk (FuncState *fs, TValue *key, TValue *v) { + lua_State *L = fs->ls->L; + Proto *f = fs->f; + TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ + int k, oldsize; + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ + } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setivalue(idx, k); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; +} + + +/* +** Add a string to list of constants and return its index. +*/ +int luaK_stringK (FuncState *fs, TString *s) { + TValue o; + setsvalue(fs->ls->L, &o, s); + return addk(fs, &o, &o); /* use string itself as key */ +} + + +/* +** Add an integer to list of constants and return its index. +** Integers use userdata as keys to avoid collision with floats with +** same value; conversion to 'void*' is used only for hashing, so there +** are no "precision" problems. +*/ +int luaK_intK (FuncState *fs, lua_Integer n) { + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); +} + +/* +** Add a float to list of constants and return its index. +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { + TValue o; + setfltvalue(&o, r); + return addk(fs, &o, &o); /* use number itself as key */ +} + + +/* +** Add a boolean to list of constants and return its index. +*/ +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); /* use boolean itself as key */ +} + + +/* +** Add nil to list of constants and return its index. +*/ +static int nilK (FuncState *fs) { + TValue k, v; + setnilvalue(&v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->ls->L, &k, fs->ls->h); + return addk(fs, &k, &v); +} + + +/* +** Fix an expression to return the number of results 'nresults'. +** Either 'e' is a multi-ret expression (function call or vararg) +** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). +*/ +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getinstruction(fs, e), nresults + 1); + } + else if (e->k == VVARARG) { + Instruction *pc = &getinstruction(fs, e); + SETARG_B(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); + luaK_reserveregs(fs, 1); + } + else lua_assert(nresults == LUA_MULTRET); +} + + +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOCABLE (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getinstruction(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ + } +} + + +/* +** Ensure that expression 'e' is not a variable. +*/ +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { /* already in a register */ + e->k = VNONRELOC; /* becomes a non-relocatable value */ + break; + } + case VUPVAL: { /* move value to some (pending) register */ + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + OpCode op; + freereg(fs, e->u.ind.idx); + if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ + freereg(fs, e->u.ind.t); + op = OP_GETTABLE; + } + else { + lua_assert(e->u.ind.vt == VUPVAL); + op = OP_GETTABUP; /* 't' is in an upvalue */ + } + e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOCABLE; + break; + } + case VVARARG: case VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } +} + + +/* +** Ensures expression value is in register 'reg' (and therefore +** 'e' will become a non-relocatable expression). +*/ +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: { + luaK_codek(fs, reg, e->u.info); + break; + } + case VKFLT: { + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); + break; + } + case VKINT: { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } + case VRELOCABLE: { + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ + break; + } + case VNONRELOC: { + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); + break; + } + default: { + lua_assert(e->k == VJMP); + return; /* nothing to do... */ + } + } + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures expression value is in any register. +*/ +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ + } +} + + +static int code_loadbool (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ +static void exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t) || need_value(fs, e->f)) { + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_loadbool(fs, reg, 0, 1); + p_t = code_loadbool(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); + } + e->f = e->t = NO_JUMP; + e->u.info = reg; + e->k = VNONRELOC; +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in next available register. +*/ +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs->freereg - 1); +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in some (any) register and return that register. +*/ +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ + if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put final result in it */ + return e->u.info; + } + } + luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ + return e->u.info; +} + + +/* +** Ensures final expression result is either in a register or in an +** upvalue. +*/ +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + +/* +** Ensures final expression result is either in a register or it is +** a constant. +*/ +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} + + +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns R/K index. +*/ +int luaK_exp2RK (FuncState *fs, expdesc *e) { + luaK_exp2val(fs, e); + switch (e->k) { /* move constants to 'k' */ + case VTRUE: e->u.info = boolK(fs, 1); goto vk; + case VFALSE: e->u.info = boolK(fs, 0); goto vk; + case VNIL: e->u.info = nilK(fs); goto vk; + case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; + case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; + case VK: + vk: + e->k = VK; + if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ + return RKASK(e->u.info); + else break; + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} + + +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); + break; + } + case VINDEXED: { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); + break; + } + default: lua_assert(0); /* invalid var kind to store */ + } + freeexp(fs, ex); +} + + +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ + freeexp(fs, e); + e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); + freeexp(fs, key); +} + + +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.info); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); +} + + +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOCABLE) { + Instruction ie = getinstruction(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); +} + + +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ + break; + } + case VK: case VKFLT: case VKINT: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 0); /* jump when false */ + break; + } + } + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ + e->t = NO_JUMP; +} + + +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of new jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VJMP: { + pc = e->u.info; /* already jump if true */ + break; + } + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + default: { + pc = jumponcond(fs, e, 1); /* jump if true */ + break; + } + } + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ + e->f = NO_JUMP; +} + + +/* +** Code 'not e', doing constant folding. +*/ +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; /* true == not nil == not false */ + break; + } + case VK: case VKFLT: case VKINT: case VTRUE: { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ + break; + } + case VJMP: { + negatecondition(fs, e); + break; + } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); + e->k = VRELOCABLE; + break; + } + default: lua_assert(0); /* cannot happen */ + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); /* values are useless when negated */ + removevalues(fs, e->t); +} + + +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. +*/ +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); + t->u.ind.t = t->u.info; /* register or upvalue index */ + t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; + t->k = VINDEXED; +} + + +/* +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (tointeger(v1, &i) && tointeger(v2, &i)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } +} + + +/* +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, + const expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; +} + + +/* +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). +** Expression to produce final result will be encoded in 'e1'. +** Because 'luaK_exp2RK' can free registers, its calls must be +** in "stack order" (that is, first on 'e2', which may have more +** recent registers to be released). +*/ +static void codebinexpval (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ + int rk1 = luaK_exp2RK(fs, e1); + freeexps(fs, e1, e2); + e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for comparisons. +** 'e1' was already put in R/K form by 'luaK_infix'. +*/ +static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int rk1 = (e1->k == VK) ? RKASK(e1->u.info) + : check_exp(e1->k == VNONRELOC, e1->u.info); + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + switch (opr) { + case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ + e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ + break; + } + default: { /* '==', '<', '<=' use their own opcodes */ + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk1, rk2); + break; + } + } + e1->k = VJMP; +} + + +/* +** Aplly prefix operation 'op' to expression 'e'. +*/ +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { + static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; + switch (op) { + case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ + if (constfolding(fs, op + LUA_OPUNM, e, &ef)) + break; + /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); + break; + case OPR_NOT: codenot(fs, e); break; + default: lua_assert(0); + } +} + + +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ + break; + } + case OPR_OR: { + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ + break; + } + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ + break; + } + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be folded with 2nd operand */ + break; + } + default: { + luaK_exp2RK(fs, v); + break; + } + } +} + + +/* +** Finalize code for binary operation, after reading 2nd operand. +** For '(a .. b .. c)' (which is '(a .. (b .. c))', because +** concatenation is right associative), merge second CONCAT into first +** one. +*/ +void luaK_posfix (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { + switch (op) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && + GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getinstruction(fs, e2), e1->u.info); + e1->k = VRELOCABLE; e1->u.info = e2->u.info; + } + else { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codebinexpval(fs, OP_CONCAT, e1, e2, line); + } + break; + } + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_IDIV: case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!constfolding(fs, op + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, op, e1, e2); + break; + } + default: lua_assert(0); + } +} + + +/* +** Change line information associated with current position. +*/ +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else if (c <= MAXARG_Ax) { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + codeextraarg(fs, c); + } + else + luaX_syntaxerror(fs->ls, "constructor too long"); + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/libs/lua/source/lcorolib.c b/libs/lua/source/lcorolib.c index 0b17af9e..db1657f1 100644 --- a/libs/lua/source/lcorolib.c +++ b/libs/lua/source/lcorolib.c @@ -1,168 +1,168 @@ -/* -** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $ -** Coroutine Library -** See Copyright Notice in lua.h -*/ - -#define lcorolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -static lua_State *getco (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "thread expected"); - return co; -} - - -static int auxresume (lua_State *L, lua_State *co, int narg) { - int status; - if (!lua_checkstack(co, narg)) { - lua_pushliteral(L, "too many arguments to resume"); - return -1; /* error flag */ - } - if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { - lua_pushliteral(L, "cannot resume dead coroutine"); - return -1; /* error flag */ - } - lua_xmove(L, co, narg); - status = lua_resume(co, L, narg); - if (status == LUA_OK || status == LUA_YIELD) { - int nres = lua_gettop(co); - if (!lua_checkstack(L, nres + 1)) { - lua_pop(co, nres); /* remove results anyway */ - lua_pushliteral(L, "too many results to resume"); - return -1; /* error flag */ - } - lua_xmove(co, L, nres); /* move yielded values */ - return nres; - } - else { - lua_xmove(co, L, 1); /* move error message */ - return -1; /* error flag */ - } -} - - -static int luaB_coresume (lua_State *L) { - lua_State *co = getco(L); - int r; - r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); - return r + 1; /* return true + 'resume' returns */ - } -} - - -static int luaB_auxwrap (lua_State *L) { - lua_State *co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { - if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ - luaL_where(L, 1); /* add extra info */ - lua_insert(L, -2); - lua_concat(L, 2); - } - return lua_error(L); /* propagate error */ - } - return r; -} - - -static int luaB_cocreate (lua_State *L) { - lua_State *NL; - luaL_checktype(L, 1, LUA_TFUNCTION); - NL = lua_newthread(L); - lua_pushvalue(L, 1); /* move function to top */ - lua_xmove(L, NL, 1); /* move function from L to NL */ - return 1; -} - - -static int luaB_cowrap (lua_State *L) { - luaB_cocreate(L); - lua_pushcclosure(L, luaB_auxwrap, 1); - return 1; -} - - -static int luaB_yield (lua_State *L) { - return lua_yield(L, lua_gettop(L)); -} - - -static int luaB_costatus (lua_State *L) { - lua_State *co = getco(L); - if (L == co) lua_pushliteral(L, "running"); - else { - switch (lua_status(co)) { - case LUA_YIELD: - lua_pushliteral(L, "suspended"); - break; - case LUA_OK: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - lua_pushliteral(L, "normal"); /* it is running */ - else if (lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); /* initial state */ - break; - } - default: /* some error occurred */ - lua_pushliteral(L, "dead"); - break; - } - } - return 1; -} - - -static int luaB_yieldable (lua_State *L) { - lua_pushboolean(L, lua_isyieldable(L)); - return 1; -} - - -static int luaB_corunning (lua_State *L) { - int ismain = lua_pushthread(L); - lua_pushboolean(L, ismain); - return 2; -} - - -static const luaL_Reg co_funcs[] = { - {"create", luaB_cocreate}, - {"resume", luaB_coresume}, - {"running", luaB_corunning}, - {"status", luaB_costatus}, - {"wrap", luaB_cowrap}, - {"yield", luaB_yield}, - {"isyieldable", luaB_yieldable}, - {NULL, NULL} -}; - - - -LUAMOD_API int luaopen_coroutine (lua_State *L) { - luaL_newlib(L, co_funcs); - return 1; -} - +/* +** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $ +** Coroutine Library +** See Copyright Notice in lua.h +*/ + +#define lcorolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "thread expected"); + return co; +} + + +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status; + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, L, narg); + if (status == LUA_OK || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = getco(L); + int r; + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + 'resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + return lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL; + luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = getco(L); + if (L == co) lua_pushliteral(L, "running"); + else { + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } + return 1; +} + + +static int luaB_yieldable (lua_State *L) { + lua_pushboolean(L, lua_isyieldable(L)); + return 1; +} + + +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_coroutine (lua_State *L) { + luaL_newlib(L, co_funcs); + return 1; +} + diff --git a/libs/lua/source/lctype.c b/libs/lua/source/lctype.c index f8ad7a2e..9371dd99 100644 --- a/libs/lua/source/lctype.c +++ b/libs/lua/source/lctype.c @@ -1,55 +1,55 @@ -/* -** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $ -** 'ctype' functions for Lua -** See Copyright Notice in lua.h -*/ - -#define lctype_c -#define LUA_CORE - -#include "lprefix.h" - - -#include "lctype.h" - -#if !LUA_USE_CTYPE /* { */ - -#include - -LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { - 0x00, /* EOZ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ - 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ - 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ - 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -#endif /* } */ +/* +** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#define lctype_c +#define LUA_CORE + +#include "lprefix.h" + + +#include "lctype.h" + +#if !LUA_USE_CTYPE /* { */ + +#include + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif /* } */ diff --git a/libs/lua/source/ldblib.c b/libs/lua/source/ldblib.c index 9d29afb0..39c37a72 100644 --- a/libs/lua/source/ldblib.c +++ b/libs/lua/source/ldblib.c @@ -1,456 +1,456 @@ -/* -** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - -#define ldblib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** The hook table at registry[&HOOKKEY] maps threads to their current -** hook function. (We only need the unique address of 'HOOKKEY'.) -*/ -static const int HOOKKEY = 0; - - -/* -** If L1 != L, L1 can be in any state, and therefore there are no -** guarantees about its stack space; any push in L1 must be -** checked. -*/ -static void checkstack (lua_State *L, lua_State *L1, int n) { - if (L != L1 && !lua_checkstack(L1, n)) - luaL_error(L, "stack overflow"); -} - - -static int db_getregistry (lua_State *L) { - lua_pushvalue(L, LUA_REGISTRYINDEX); - return 1; -} - - -static int db_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); /* no metatable */ - } - return 1; -} - - -static int db_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; /* return 1st argument */ -} - - -static int db_getuservalue (lua_State *L) { - if (lua_type(L, 1) != LUA_TUSERDATA) - lua_pushnil(L); - else - lua_getuservalue(L, 1); - return 1; -} - - -static int db_setuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_setuservalue(L, 1); - return 1; -} - - -/* -** Auxiliary function used by several library functions: check for -** an optional thread as function's first argument and set 'arg' with -** 1 if this argument is present (so that functions can skip it to -** access their other arguments) -*/ -static lua_State *getthread (lua_State *L, int *arg) { - if (lua_isthread(L, 1)) { - *arg = 1; - return lua_tothread(L, 1); - } - else { - *arg = 0; - return L; /* function will operate over current thread */ - } -} - - -/* -** Variations of 'lua_settable', used by 'db_getinfo' to put results -** from 'lua_getinfo' into result table. Key is always a string; -** value can be a string, an int, or a boolean. -*/ -static void settabss (lua_State *L, const char *k, const char *v) { - lua_pushstring(L, v); - lua_setfield(L, -2, k); -} - -static void settabsi (lua_State *L, const char *k, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, k); -} - -static void settabsb (lua_State *L, const char *k, int v) { - lua_pushboolean(L, v); - lua_setfield(L, -2, k); -} - - -/* -** In function 'db_getinfo', the call to 'lua_getinfo' may push -** results on the stack; later it creates the result table to put -** these objects. Function 'treatstackoption' puts the result from -** 'lua_getinfo' on top of the result table so that it can call -** 'lua_setfield'. -*/ -static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { - if (L == L1) - lua_rotate(L, -2, 1); /* exchange object and table */ - else - lua_xmove(L1, L, 1); /* move object to the "main" stack */ - lua_setfield(L, -2, fname); /* put object into table */ -} - - -/* -** Calls 'lua_getinfo' and collects all results in a new table. -** L1 needs stack space for an optional input (function) plus -** two optional outputs (function and line table) from function -** 'lua_getinfo'. -*/ -static int db_getinfo (lua_State *L) { - lua_Debug ar; - int arg; - lua_State *L1 = getthread(L, &arg); - const char *options = luaL_optstring(L, arg+2, "flnStu"); - checkstack(L, L1, 3); - if (lua_isfunction(L, arg + 1)) { /* info about a function? */ - options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ - lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ - lua_xmove(L, L1, 1); - } - else { /* stack level */ - if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { - lua_pushnil(L); /* level out of range */ - return 1; - } - } - if (!lua_getinfo(L1, options, &ar)) - return luaL_argerror(L, arg+2, "invalid option"); - lua_newtable(L); /* table to collect results */ - if (strchr(options, 'S')) { - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabsi(L, "lastlinedefined", ar.lastlinedefined); - settabss(L, "what", ar.what); - } - if (strchr(options, 'l')) - settabsi(L, "currentline", ar.currentline); - if (strchr(options, 'u')) { - settabsi(L, "nups", ar.nups); - settabsi(L, "nparams", ar.nparams); - settabsb(L, "isvararg", ar.isvararg); - } - if (strchr(options, 'n')) { - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - } - if (strchr(options, 't')) - settabsb(L, "istailcall", ar.istailcall); - if (strchr(options, 'L')) - treatstackoption(L, L1, "activelines"); - if (strchr(options, 'f')) - treatstackoption(L, L1, "func"); - return 1; /* return table */ -} - - -static int db_getlocal (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - const char *name; - int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ - if (lua_isfunction(L, arg + 1)) { /* function argument? */ - lua_pushvalue(L, arg + 1); /* push function */ - lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ - return 1; /* return only name (there is no value) */ - } - else { /* stack-level argument */ - int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - checkstack(L, L1, 1); - name = lua_getlocal(L1, &ar, nvar); - if (name) { - lua_xmove(L1, L, 1); /* move local value */ - lua_pushstring(L, name); /* push name */ - lua_rotate(L, -2, 1); /* re-order */ - return 2; - } - else { - lua_pushnil(L); /* no name (nor value) */ - return 1; - } - } -} - - -static int db_setlocal (lua_State *L) { - int arg; - const char *name; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - int level = (int)luaL_checkinteger(L, arg + 1); - int nvar = (int)luaL_checkinteger(L, arg + 2); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - luaL_checkany(L, arg+3); - lua_settop(L, arg+3); - checkstack(L, L1, 1); - lua_xmove(L, L1, 1); - name = lua_setlocal(L1, &ar, nvar); - if (name == NULL) - lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ - lua_pushstring(L, name); - return 1; -} - - -/* -** get (if 'get' is true) or set an upvalue from a closure -*/ -static int auxupvalue (lua_State *L, int get) { - const char *name; - int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ - luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ - name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - lua_insert(L, -(get+1)); /* no-op if get is false */ - return get + 1; -} - - -static int db_getupvalue (lua_State *L) { - return auxupvalue(L, 1); -} - - -static int db_setupvalue (lua_State *L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); -} - - -/* -** Check whether a given upvalue from a given closure exists and -** returns its index -*/ -static int checkupval (lua_State *L, int argf, int argnup) { - int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ - luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ - luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, - "invalid upvalue index"); - return nup; -} - - -static int db_upvalueid (lua_State *L) { - int n = checkupval(L, 1, 2); - lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); - return 1; -} - - -static int db_upvaluejoin (lua_State *L) { - int n1 = checkupval(L, 1, 2); - int n2 = checkupval(L, 3, 4); - luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); - luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); - lua_upvaluejoin(L, 1, n1, 3, n2); - return 0; -} - - -/* -** Call hook function registered at hook table for the current -** thread (if there is one) -*/ -static void hookf (lua_State *L, lua_Debug *ar) { - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail call"}; - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - lua_pushthread(L); - if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ - lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ - if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); /* push current line */ - else lua_pushnil(L); - lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); /* call hook function */ - } -} - - -/* -** Convert a string mask (for 'sethook') into a bit mask -*/ -static int makemask (const char *smask, int count) { - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - return mask; -} - - -/* -** Convert a bit mask (for 'gethook') into a string mask -*/ -static char *unmakemask (int mask, char *smask) { - int i = 0; - if (mask & LUA_MASKCALL) smask[i++] = 'c'; - if (mask & LUA_MASKRET) smask[i++] = 'r'; - if (mask & LUA_MASKLINE) smask[i++] = 'l'; - smask[i] = '\0'; - return smask; -} - - -static int db_sethook (lua_State *L) { - int arg, mask, count; - lua_Hook func; - lua_State *L1 = getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { /* no hook? */ - lua_settop(L, arg+1); - func = NULL; mask = 0; count = 0; /* turn off hooks */ - } - else { - const char *smask = luaL_checkstring(L, arg+2); - luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = (int)luaL_optinteger(L, arg + 3, 0); - func = hookf; mask = makemask(smask, count); - } - if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { - lua_createtable(L, 0, 2); /* create a hook table */ - lua_pushvalue(L, -1); - lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ - lua_pushstring(L, "k"); - lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ - lua_pushvalue(L, -1); - lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ - } - checkstack(L, L1, 1); - lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ - lua_pushvalue(L, arg + 1); /* value (hook function) */ - lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ - lua_sethook(L1, func, mask, count); - return 0; -} - - -static int db_gethook (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - char buff[5]; - int mask = lua_gethookmask(L1); - lua_Hook hook = lua_gethook(L1); - if (hook == NULL) /* no hook? */ - lua_pushnil(L); - else if (hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { /* hook table must exist */ - lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); - checkstack(L, L1, 1); - lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_rawget(L, -2); /* 1st result = hooktable[L1] */ - lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ - lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ - return 3; -} - - -static int db_debug (lua_State *L) { - for (;;) { - char buffer[250]; - lua_writestringerror("%s", "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) - lua_writestringerror("%s\n", lua_tostring(L, -1)); - lua_settop(L, 0); /* remove eventual returns */ - } -} - - -static int db_traceback (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - const char *msg = lua_tostring(L, arg + 1); - if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ - lua_pushvalue(L, arg + 1); /* return it untouched */ - else { - int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); - luaL_traceback(L, L1, msg, level); - } - return 1; -} - - -static const luaL_Reg dblib[] = { - {"debug", db_debug}, - {"getuservalue", db_getuservalue}, - {"gethook", db_gethook}, - {"getinfo", db_getinfo}, - {"getlocal", db_getlocal}, - {"getregistry", db_getregistry}, - {"getmetatable", db_getmetatable}, - {"getupvalue", db_getupvalue}, - {"upvaluejoin", db_upvaluejoin}, - {"upvalueid", db_upvalueid}, - {"setuservalue", db_setuservalue}, - {"sethook", db_sethook}, - {"setlocal", db_setlocal}, - {"setmetatable", db_setmetatable}, - {"setupvalue", db_setupvalue}, - {"traceback", db_traceback}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_debug (lua_State *L) { - luaL_newlib(L, dblib); - return 1; -} - +/* +** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** The hook table at registry[&HOOKKEY] maps threads to their current +** hook function. (We only need the unique address of 'HOOKKEY'.) +*/ +static const int HOOKKEY = 0; + + +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +static void checkstack (lua_State *L, lua_State *L1, int n) { + if (L != L1 && !lua_checkstack(L1, n)) + luaL_error(L, "stack overflow"); +} + + +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + +static int db_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int db_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ +} + + +static int db_getuservalue (lua_State *L) { + if (lua_type(L, 1) != LUA_TUSERDATA) + lua_pushnil(L); + else + lua_getuservalue(L, 1); + return 1; +} + + +static int db_setuservalue (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_setuservalue(L, 1); + return 1; +} + + +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; /* function will operate over current thread */ + } +} + + +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ + else + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ +} + + +/* +** Calls 'lua_getinfo' and collects all results in a new table. +** L1 needs stack space for an optional input (function) plus +** two optional outputs (function and line table) from function +** 'lua_getinfo'. +*/ +static int db_getinfo (lua_State *L) { + lua_Debug ar; + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnStu"); + checkstack(L, L1, 3); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); + lua_newtable(L); /* table to collect results */ + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) { + settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); + return 1; /* return table */ +} + + +static int db_getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + const char *name; + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ + return 1; /* return only name (there is no value) */ + } + else { /* stack-level argument */ + int level = (int)luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); + name = lua_getlocal(L1, &ar, nvar); + if (name) { + lua_xmove(L1, L, 1); /* move local value */ + lua_pushstring(L, name); /* push name */ + lua_rotate(L, -2, 1); /* re-order */ + return 2; + } + else { + lua_pushnil(L); /* no name (nor value) */ + return 1; + } + } +} + + +static int db_setlocal (lua_State *L) { + int arg; + const char *name; + lua_State *L1 = getthread(L, &arg); + lua_Debug ar; + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + checkstack(L, L1, 1); + lua_xmove(L, L1, 1); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); + return 1; +} + + +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); /* no-op if get is false */ + return get + 1; +} + + +static int db_getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int db_setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ +static int checkupval (lua_State *L, int argf, int argnup) { + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, + "invalid upvalue index"); + return nup; +} + + +static int db_upvalueid (lua_State *L) { + int n = checkupval(L, 1, 2); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1 = checkupval(L, 1, 2); + int n2 = checkupval(L, 3, 4); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + + +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail call"}; + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + lua_pushthread(L); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ + if (ar->currentline >= 0) + lua_pushinteger(L, ar->currentline); /* push current line */ + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); /* call hook function */ + } +} + + +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; +} + + +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; +} + + +static int db_sethook (lua_State *L) { + int arg, mask, count; + lua_Hook func; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ + lua_settop(L, arg+1); + func = NULL; mask = 0; count = 0; /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = (int)luaL_optinteger(L, arg + 3, 0); + func = hookf; mask = makemask(smask, count); + } + if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); + return 0; +} + + +static int db_gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + char buff[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook == NULL) /* no hook? */ + lua_pushnil(L); + else if (hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { /* hook table must exist */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ + return 3; +} + + +static int db_debug (lua_State *L) { + for (;;) { + char buffer[250]; + lua_writestringerror("%s", "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || + lua_pcall(L, 0, 0, 0)) + lua_writestringerror("%s\n", lua_tostring(L, -1)); + lua_settop(L, 0); /* remove eventual returns */ + } +} + + +static int db_traceback (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); + } + return 1; +} + + +static const luaL_Reg dblib[] = { + {"debug", db_debug}, + {"getuservalue", db_getuservalue}, + {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, + {"getmetatable", db_getmetatable}, + {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, + {"setuservalue", db_setuservalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, + {"setupvalue", db_setupvalue}, + {"traceback", db_traceback}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_debug (lua_State *L) { + luaL_newlib(L, dblib); + return 1; +} + diff --git a/libs/lua/source/ldebug.c b/libs/lua/source/ldebug.c index e1389296..336d3d05 100644 --- a/libs/lua/source/ldebug.c +++ b/libs/lua/source/ldebug.c @@ -1,699 +1,699 @@ -/* -** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $ -** Debug Interface -** See Copyright Notice in lua.h -*/ - -#define ldebug_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - - -#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) - - -/* Active Lua function (given call info) */ -#define ci_func(ci) (clLvalue((ci)->func)) - - -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name); - - -static int currentpc (CallInfo *ci) { - lua_assert(isLua(ci)); - return pcRel(ci->u.l.savedpc, ci_func(ci)->p); -} - - -static int currentline (CallInfo *ci) { - return getfuncline(ci_func(ci)->p, currentpc(ci)); -} - - -/* -** If function yielded, its 'func' can be in the 'extra' field. The -** next function restores 'func' to its correct value for debugging -** purposes. (It exchanges 'func' and 'extra'; so, when called again, -** after debugging, it also "re-restores" ** 'func' to its altered value. -*/ -static void swapextra (lua_State *L) { - if (L->status == LUA_YIELD) { - CallInfo *ci = L->ci; /* get function that yielded */ - StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ - ci->func = restorestack(L, ci->extra); - ci->extra = savestack(L, temp); - } -} - - -/* -** This function can be called asynchronously (e.g. during a signal). -** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by -** 'resethookcount') are for debug only, and it is no problem if they -** get arbitrary values (causes at most one wrong hook call). 'hookmask' -** is an atomic value. We assume that pointers are atomic too (e.g., gcc -** ensures that for all platforms where it runs). Moreover, 'hook' is -** always checked before being called (see 'luaD_hook'). -*/ -LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { - if (func == NULL || mask == 0) { /* turn off hooks? */ - mask = 0; - func = NULL; - } - if (isLua(L->ci)) - L->oldpc = L->ci->u.l.savedpc; - L->hook = func; - L->basehookcount = count; - resethookcount(L); - L->hookmask = cast_byte(mask); -} - - -LUA_API lua_Hook lua_gethook (lua_State *L) { - return L->hook; -} - - -LUA_API int lua_gethookmask (lua_State *L) { - return L->hookmask; -} - - -LUA_API int lua_gethookcount (lua_State *L) { - return L->basehookcount; -} - - -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { - int status; - CallInfo *ci; - if (level < 0) return 0; /* invalid (negative) level */ - lua_lock(L); - for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) - level--; - if (level == 0 && ci != &L->base_ci) { /* level found? */ - status = 1; - ar->i_ci = ci; - } - else status = 0; /* no such level */ - lua_unlock(L); - return status; -} - - -static const char *upvalname (Proto *p, int uv) { - TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); - if (s == NULL) return "?"; - else return getstr(s); -} - - -static const char *findvararg (CallInfo *ci, int n, StkId *pos) { - int nparams = clLvalue(ci->func)->p->numparams; - if (n >= cast_int(ci->u.l.base - ci->func) - nparams) - return NULL; /* no such vararg */ - else { - *pos = ci->func + nparams + n; - return "(*vararg)"; /* generic name for any vararg */ - } -} - - -static const char *findlocal (lua_State *L, CallInfo *ci, int n, - StkId *pos) { - const char *name = NULL; - StkId base; - if (isLua(ci)) { - if (n < 0) /* access to vararg values? */ - return findvararg(ci, -n, pos); - else { - base = ci->u.l.base; - name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); - } - } - else - base = ci->func + 1; - if (name == NULL) { /* no 'standard' name? */ - StkId limit = (ci == L->ci) ? L->top : ci->next->func; - if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - name = "(*temporary)"; /* generic name for any valid slot */ - else - return NULL; /* no name */ - } - *pos = base + (n - 1); - return name; -} - - -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - lua_lock(L); - swapextra(L); - if (ar == NULL) { /* information about non-active function? */ - if (!isLfunction(L->top - 1)) /* not a Lua function? */ - name = NULL; - else /* consider live variables at function start (parameters) */ - name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); - } - else { /* active function; get information through 'ar' */ - StkId pos = NULL; /* to avoid warnings */ - name = findlocal(L, ar->i_ci, n, &pos); - if (name) { - setobj2s(L, L->top, pos); - api_incr_top(L); - } - } - swapextra(L); - lua_unlock(L); - return name; -} - - -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos = NULL; /* to avoid warnings */ - const char *name; - lua_lock(L); - swapextra(L); - name = findlocal(L, ar->i_ci, n, &pos); - if (name) { - setobjs2s(L, pos, L->top - 1); - L->top--; /* pop value */ - } - swapextra(L); - lua_unlock(L); - return name; -} - - -static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { - ar->source = "=[C]"; - ar->linedefined = -1; - ar->lastlinedefined = -1; - ar->what = "C"; - } - else { - Proto *p = cl->l.p; - ar->source = p->source ? getstr(p->source) : "=?"; - ar->linedefined = p->linedefined; - ar->lastlinedefined = p->lastlinedefined; - ar->what = (ar->linedefined == 0) ? "main" : "Lua"; - } - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); -} - - -static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { - setnilvalue(L->top); - api_incr_top(L); - } - else { - int i; - TValue v; - int *lineinfo = f->l.p->lineinfo; - Table *t = luaH_new(L); /* new table to store active lines */ - sethvalue(L, L->top, t); /* push it on stack */ - api_incr_top(L); - setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ - for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ - luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ - } -} - - -static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - if (ci == NULL) /* no 'ci'? */ - return NULL; /* no info */ - else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ - *name = "__gc"; - return "metamethod"; /* report it as such */ - } - /* calling function is a known Lua function? */ - else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) - return funcnamefromcode(L, ci->previous, name); - else return NULL; /* no way to find a name */ -} - - -static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, CallInfo *ci) { - int status = 1; - for (; *what; what++) { - switch (*what) { - case 'S': { - funcinfo(ar, f); - break; - } - case 'l': { - ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; - break; - } - case 'u': { - ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { - ar->isvararg = 1; - ar->nparams = 0; - } - else { - ar->isvararg = f->l.p->is_vararg; - ar->nparams = f->l.p->numparams; - } - break; - } - case 't': { - ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; - break; - } - case 'n': { - ar->namewhat = getfuncname(L, ci, &ar->name); - if (ar->namewhat == NULL) { - ar->namewhat = ""; /* not found */ - ar->name = NULL; - } - break; - } - case 'L': - case 'f': /* handled by lua_getinfo */ - break; - default: status = 0; /* invalid option */ - } - } - return status; -} - - -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status; - Closure *cl; - CallInfo *ci; - StkId func; - lua_lock(L); - swapextra(L); - if (*what == '>') { - ci = NULL; - func = L->top - 1; - api_check(L, ttisfunction(func), "function expected"); - what++; /* skip the '>' */ - L->top--; /* pop function */ - } - else { - ci = ar->i_ci; - func = ci->func; - lua_assert(ttisfunction(ci->func)); - } - cl = ttisclosure(func) ? clvalue(func) : NULL; - status = auxgetinfo(L, what, ar, cl, ci); - if (strchr(what, 'f')) { - setobjs2s(L, L->top, func); - api_incr_top(L); - } - swapextra(L); /* correct before option 'L', which can raise a mem. error */ - if (strchr(what, 'L')) - collectvalidlines(L, cl); - lua_unlock(L); - return status; -} - - -/* -** {====================================================== -** Symbolic Execution -** ======================================================= -*/ - -static const char *getobjname (Proto *p, int lastpc, int reg, - const char **name); - - -/* -** find a "name" for the RK value 'c' -*/ -static void kname (Proto *p, int pc, int c, const char **name) { - if (ISK(c)) { /* is 'c' a constant? */ - TValue *kvalue = &p->k[INDEXK(c)]; - if (ttisstring(kvalue)) { /* literal constant? */ - *name = svalue(kvalue); /* it is its own name */ - return; - } - /* else no reasonable name found */ - } - else { /* 'c' is a register */ - const char *what = getobjname(p, pc, c, name); /* search for 'c' */ - if (what && *what == 'c') { /* found a constant name? */ - return; /* 'name' already filled */ - } - /* else no reasonable name found */ - } - *name = "?"; /* no reasonable name found */ -} - - -static int filterpc (int pc, int jmptarget) { - if (pc < jmptarget) /* is code conditional (inside a jump)? */ - return -1; /* cannot know who sets that register */ - else return pc; /* current position sets that register */ -} - - -/* -** try to find last instruction before 'lastpc' that modified register 'reg' -*/ -static int findsetreg (Proto *p, int lastpc, int reg) { - int pc; - int setreg = -1; /* keep last instruction that changed 'reg' */ - int jmptarget = 0; /* any code before this address is conditional */ - for (pc = 0; pc < lastpc; pc++) { - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); - int a = GETARG_A(i); - switch (op) { - case OP_LOADNIL: { - int b = GETARG_B(i); - if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_TFORCALL: { - if (reg >= a + 2) /* affect all regs above its base */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_CALL: - case OP_TAILCALL: { - if (reg >= a) /* affect all registers above base */ - setreg = filterpc(pc, jmptarget); - break; - } - case OP_JMP: { - int b = GETARG_sBx(i); - int dest = pc + 1 + b; - /* jump is forward and do not skip 'lastpc'? */ - if (pc < dest && dest <= lastpc) { - if (dest > jmptarget) - jmptarget = dest; /* update 'jmptarget' */ - } - break; - } - default: - if (testAMode(op) && reg == a) /* any instruction that set A */ - setreg = filterpc(pc, jmptarget); - break; - } - } - return setreg; -} - - -static const char *getobjname (Proto *p, int lastpc, int reg, - const char **name) { - int pc; - *name = luaF_getlocalname(p, reg + 1, lastpc); - if (*name) /* is a local? */ - return "local"; - /* else try symbolic execution */ - pc = findsetreg(p, lastpc, reg); - if (pc != -1) { /* could find instruction? */ - Instruction i = p->code[pc]; - OpCode op = GET_OPCODE(i); - switch (op) { - case OP_MOVE: { - int b = GETARG_B(i); /* move from 'b' to 'a' */ - if (b < GETARG_A(i)) - return getobjname(p, pc, b, name); /* get name for 'b' */ - break; - } - case OP_GETTABUP: - case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - int t = GETARG_B(i); /* table index */ - const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ - ? luaF_getlocalname(p, t + 1, pc) - : upvalname(p, t); - kname(p, pc, k, name); - return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; - } - case OP_GETUPVAL: { - *name = upvalname(p, GETARG_B(i)); - return "upvalue"; - } - case OP_LOADK: - case OP_LOADKX: { - int b = (op == OP_LOADK) ? GETARG_Bx(i) - : GETARG_Ax(p->code[pc + 1]); - if (ttisstring(&p->k[b])) { - *name = svalue(&p->k[b]); - return "constant"; - } - break; - } - case OP_SELF: { - int k = GETARG_C(i); /* key index */ - kname(p, pc, k, name); - return "method"; - } - default: break; /* go through to return NULL */ - } - } - return NULL; /* could not find reasonable name */ -} - - -/* -** Try to find a name for a function based on the code that called it. -** (Only works when function was called by a Lua function.) -** Returns what the name is (e.g., "for iterator", "method", -** "metamethod") and sets '*name' to point to the name. -*/ -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name) { - TMS tm = (TMS)0; /* (initial value avoids warnings) */ - Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ - Instruction i = p->code[pc]; /* calling instruction */ - if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ - *name = "?"; - return "hook"; - } - switch (GET_OPCODE(i)) { - case OP_CALL: - case OP_TAILCALL: - return getobjname(p, pc, GETARG_A(i), name); /* get function name */ - case OP_TFORCALL: { /* for iterator */ - *name = "for iterator"; - return "for iterator"; - } - /* other instructions can do calls through metamethods */ - case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: - tm = TM_INDEX; - break; - case OP_SETTABUP: case OP_SETTABLE: - tm = TM_NEWINDEX; - break; - case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: - case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: - case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { - int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ - tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ - break; - } - case OP_UNM: tm = TM_UNM; break; - case OP_BNOT: tm = TM_BNOT; break; - case OP_LEN: tm = TM_LEN; break; - case OP_CONCAT: tm = TM_CONCAT; break; - case OP_EQ: tm = TM_EQ; break; - case OP_LT: tm = TM_LT; break; - case OP_LE: tm = TM_LE; break; - default: - return NULL; /* cannot find a reasonable name */ - } - *name = getstr(G(L)->tmname[tm]); - return "metamethod"; -} - -/* }====================================================== */ - - - -/* -** The subtraction of two potentially unrelated pointers is -** not ISO C, but it should not crash a program; the subsequent -** checks are ISO C and ensure a correct result. -*/ -static int isinstack (CallInfo *ci, const TValue *o) { - ptrdiff_t i = o - ci->u.l.base; - return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); -} - - -/* -** Checks whether value 'o' came from an upvalue. (That can only happen -** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on -** upvalues.) -*/ -static const char *getupvalname (CallInfo *ci, const TValue *o, - const char **name) { - LClosure *c = ci_func(ci); - int i; - for (i = 0; i < c->nupvalues; i++) { - if (c->upvals[i]->v == o) { - *name = upvalname(c->p, i); - return "upvalue"; - } - } - return NULL; -} - - -static const char *varinfo (lua_State *L, const TValue *o) { - const char *name = NULL; /* to avoid warnings */ - CallInfo *ci = L->ci; - const char *kind = NULL; - if (isLua(ci)) { - kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ - if (!kind && isinstack(ci, o)) /* no? try a register */ - kind = getobjname(ci_func(ci)->p, currentpc(ci), - cast_int(o - ci->u.l.base), &name); - } - return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; -} - - -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { - const char *t = luaT_objtypename(L, o); - luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); -} - - -l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { - if (ttisstring(p1) || cvt2str(p1)) p1 = p2; - luaG_typeerror(L, p1, "concatenate"); -} - - -l_noret luaG_opinterror (lua_State *L, const TValue *p1, - const TValue *p2, const char *msg) { - lua_Number temp; - if (!tonumber(p1, &temp)) /* first operand is wrong? */ - p2 = p1; /* now second is wrong */ - luaG_typeerror(L, p2, msg); -} - - -/* -** Error when both values are convertible to numbers, but not to integers -*/ -l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { - lua_Integer temp; - if (!tointeger(p1, &temp)) - p2 = p1; - luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); -} - - -l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = luaT_objtypename(L, p1); - const char *t2 = luaT_objtypename(L, p2); - if (strcmp(t1, t2) == 0) - luaG_runerror(L, "attempt to compare two %s values", t1); - else - luaG_runerror(L, "attempt to compare %s with %s", t1, t2); -} - - -/* add src:line information to 'msg' */ -const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, - int line) { - char buff[LUA_IDSIZE]; - if (src) - luaO_chunkid(buff, getstr(src), LUA_IDSIZE); - else { /* no source available; use "?" instead */ - buff[0] = '?'; buff[1] = '\0'; - } - return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); -} - - -l_noret luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - setobjs2s(L, L->top, L->top - 1); /* move argument */ - setobjs2s(L, L->top - 1, errfunc); /* push function */ - L->top++; /* assume EXTRA_STACK */ - luaD_callnoyield(L, L->top - 2, 1); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); -} - - -l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { - CallInfo *ci = L->ci; - const char *msg; - va_list argp; - luaC_checkGC(L); /* error message uses memory */ - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); /* format message */ - va_end(argp); - if (isLua(ci)) /* if Lua function, add source:line information */ - luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); - luaG_errormsg(L); -} - - -void luaG_traceexec (lua_State *L) { - CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); - if (counthook) - resethookcount(L); /* reset count */ - else if (!(mask & LUA_MASKLINE)) - return; /* no line hook and count != 0; nothing to be done */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ - ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ - return; /* do not call hook again (VM yielded, so it did not move) */ - } - if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->p; - int npc = pcRel(ci->u.l.savedpc, p); - int newline = getfuncline(p, npc); - if (npc == 0 || /* call linehook when enter a new function, */ - ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ - newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ - luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ - } - L->oldpc = ci->u.l.savedpc; - if (L->status == LUA_YIELD) { /* did hook yield? */ - if (counthook) - L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ - ci->func = L->top - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); - } -} - +/* +** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + + +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) + + +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + + +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + const char **name); + + +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); +} + + +static int currentline (CallInfo *ci) { + return getfuncline(ci_func(ci)->p, currentpc(ci)); +} + + +/* +** If function yielded, its 'func' can be in the 'extra' field. The +** next function restores 'func' to its correct value for debugging +** purposes. (It exchanges 'func' and 'extra'; so, when called again, +** after debugging, it also "re-restores" ** 'func' to its altered value. +*/ +static void swapextra (lua_State *L) { + if (L->status == LUA_YIELD) { + CallInfo *ci = L->ci; /* get function that yielded */ + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ + ci->func = restorestack(L, ci->extra); + ci->extra = savestack(L, temp); + } +} + + +/* +** This function can be called asynchronously (e.g. during a signal). +** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by +** 'resethookcount') are for debug only, and it is no problem if they +** get arbitrary values (causes at most one wrong hook call). 'hookmask' +** is an atomic value. We assume that pointers are atomic too (e.g., gcc +** ensures that for all platforms where it runs). Moreover, 'hook' is +** always checked before being called (see 'luaD_hook'). +*/ +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; + } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast_byte(mask); +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; +} + + +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ + lua_lock(L); + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) + level--; + if (level == 0 && ci != &L->base_ci) { /* level found? */ + status = 1; + ar->i_ci = ci; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; +} + + +static const char *upvalname (Proto *p, int uv) { + TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); +} + + +static const char *findvararg (CallInfo *ci, int n, StkId *pos) { + int nparams = clLvalue(ci->func)->p->numparams; + if (n >= cast_int(ci->u.l.base - ci->func) - nparams) + return NULL; /* no such vararg */ + else { + *pos = ci->func + nparams + n; + return "(*vararg)"; /* generic name for any vararg */ + } +} + + +static const char *findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos) { + const char *name = NULL; + StkId base; + if (isLua(ci)) { + if (n < 0) /* access to vararg values? */ + return findvararg(ci, -n, pos); + else { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } + } + else + base = ci->func + 1; + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = "(*temporary)"; /* generic name for any valid slot */ + else + return NULL; /* no name */ + } + *pos = base + (n - 1); + return name; +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + lua_lock(L); + swapextra(L); + if (ar == NULL) { /* information about non-active function? */ + if (!isLfunction(L->top - 1)) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos = NULL; /* to avoid warnings */ + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobj2s(L, L->top, pos); + api_incr_top(L); + } + } + swapextra(L); + lua_unlock(L); + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + StkId pos = NULL; /* to avoid warnings */ + const char *name; + lua_lock(L); + swapextra(L); + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobjs2s(L, pos, L->top - 1); + L->top--; /* pop value */ + } + swapextra(L); + lua_unlock(L); + return name; +} + + +static void funcinfo (lua_Debug *ar, Closure *cl) { + if (noLuaClosure(cl)) { + ar->source = "=[C]"; + ar->linedefined = -1; + ar->lastlinedefined = -1; + ar->what = "C"; + } + else { + Proto *p = cl->l.p; + ar->source = p->source ? getstr(p->source) : "=?"; + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (noLuaClosure(f)) { + setnilvalue(L->top); + api_incr_top(L); + } + else { + int i; + TValue v; + int *lineinfo = f->l.p->lineinfo; + Table *t = luaH_new(L); /* new table to store active lines */ + sethvalue(L, L->top, t); /* push it on stack */ + api_incr_top(L); + setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ + for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ + luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ + } +} + + +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + if (ci == NULL) /* no 'ci'? */ + return NULL; /* no info */ + else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + /* calling function is a known Lua function? */ + else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) + return funcnamefromcode(L, ci->previous, name); + else return NULL; /* no way to find a name */ +} + + +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + Closure *f, CallInfo *ci) { + int status = 1; + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(ar, f); + break; + } + case 'l': { + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; + break; + } + case 'u': { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (noLuaClosure(f)) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; + break; + } + case 'n': { + ar->namewhat = getfuncname(L, ci, &ar->name); + if (ar->namewhat == NULL) { + ar->namewhat = ""; /* not found */ + ar->name = NULL; + } + break; + } + case 'L': + case 'f': /* handled by lua_getinfo */ + break; + default: status = 0; /* invalid option */ + } + } + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status; + Closure *cl; + CallInfo *ci; + StkId func; + lua_lock(L); + swapextra(L); + if (*what == '>') { + ci = NULL; + func = L->top - 1; + api_check(L, ttisfunction(func), "function expected"); + what++; /* skip the '>' */ + L->top--; /* pop function */ + } + else { + ci = ar->i_ci; + func = ci->func; + lua_assert(ttisfunction(ci->func)); + } + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); + if (strchr(what, 'f')) { + setobjs2s(L, L->top, func); + api_incr_top(L); + } + swapextra(L); /* correct before option 'L', which can raise a mem. error */ + if (strchr(what, 'L')) + collectvalidlines(L, cl); + lua_unlock(L); + return status; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name); + + +/* +** find a "name" for the RK value 'c' +*/ +static void kname (Proto *p, int pc, int c, const char **name) { + if (ISK(c)) { /* is 'c' a constant? */ + TValue *kvalue = &p->k[INDEXK(c)]; + if (ttisstring(kvalue)) { /* literal constant? */ + *name = svalue(kvalue); /* it is its own name */ + return; + } + /* else no reasonable name found */ + } + else { /* 'c' is a register */ + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ + if (what && *what == 'c') { /* found a constant name? */ + return; /* 'name' already filled */ + } + /* else no reasonable name found */ + } + *name = "?"; /* no reasonable name found */ +} + + +static int filterpc (int pc, int jmptarget) { + if (pc < jmptarget) /* is code conditional (inside a jump)? */ + return -1; /* cannot know who sets that register */ + else return pc; /* current position sets that register */ +} + + +/* +** try to find last instruction before 'lastpc' that modified register 'reg' +*/ +static int findsetreg (Proto *p, int lastpc, int reg) { + int pc; + int setreg = -1; /* keep last instruction that changed 'reg' */ + int jmptarget = 0; /* any code before this address is conditional */ + for (pc = 0; pc < lastpc; pc++) { + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + switch (op) { + case OP_LOADNIL: { + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_TFORCALL: { + if (reg >= a + 2) /* affect all regs above its base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_CALL: + case OP_TAILCALL: { + if (reg >= a) /* affect all registers above base */ + setreg = filterpc(pc, jmptarget); + break; + } + case OP_JMP: { + int b = GETARG_sBx(i); + int dest = pc + 1 + b; + /* jump is forward and do not skip 'lastpc'? */ + if (pc < dest && dest <= lastpc) { + if (dest > jmptarget) + jmptarget = dest; /* update 'jmptarget' */ + } + break; + } + default: + if (testAMode(op) && reg == a) /* any instruction that set A */ + setreg = filterpc(pc, jmptarget); + break; + } + } + return setreg; +} + + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name) { + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + int t = GETARG_B(i); /* table index */ + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : upvalname(p, t); + kname(p, pc, k, name); + return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; + } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: { + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + kname(p, pc, k, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** Try to find a name for a function based on the code that called it. +** (Only works when function was called by a Lua function.) +** Returns what the name is (e.g., "for iterator", "method", +** "metamethod") and sets '*name' to point to the name. +*/ +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, + const char **name) { + TMS tm = (TMS)0; /* (initial value avoids warnings) */ + Proto *p = ci_func(ci)->p; /* calling function */ + int pc = currentpc(ci); /* calling instruction index */ + Instruction i = p->code[pc]; /* calling instruction */ + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + return getobjname(p, pc, GETARG_A(i), name); /* get function name */ + case OP_TFORCALL: { /* for iterator */ + *name = "for iterator"; + return "for iterator"; + } + /* other instructions can do calls through metamethods */ + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: + tm = TM_NEWINDEX; + break; + case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: + case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: + case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { + int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ + tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ + break; + } + case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; + case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; + case OP_LT: tm = TM_LT; break; + case OP_LE: tm = TM_LE; break; + default: + return NULL; /* cannot find a reasonable name */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; +} + +/* }====================================================== */ + + + +/* +** The subtraction of two potentially unrelated pointers is +** not ISO C, but it should not crash a program; the subsequent +** checks are ISO C and ensure a correct result. +*/ +static int isinstack (CallInfo *ci, const TValue *o) { + ptrdiff_t i = o - ci->u.l.base; + return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); +} + + +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = ci_func(ci); + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = upvalname(c->p, i); + return "upvalue"; + } + } + return NULL; +} + + +static const char *varinfo (lua_State *L, const TValue *o) { + const char *name = NULL; /* to avoid warnings */ + CallInfo *ci = L->ci; + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), + cast_int(o - ci->u.l.base), &name); + } + return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; +} + + +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; + luaG_typeerror(L, p1, "concatenate"); +} + + +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + lua_Number temp; + if (!tonumber(p1, &temp)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!tointeger(p1, &temp)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); +} + + +l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); +} + + +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; + } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +} + + +l_noret luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + L->top++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; + va_list argp; + luaC_checkGC(L); /* error message uses memory */ + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ + va_end(argp); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); + luaG_errormsg(L); +} + + +void luaG_traceexec (lua_State *L) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return; /* no line hook and count != 0; nothing to be done */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } +} + diff --git a/libs/lua/source/ldo.c b/libs/lua/source/ldo.c index 316e45c8..490941e6 100644 --- a/libs/lua/source/ldo.c +++ b/libs/lua/source/ldo.c @@ -1,802 +1,802 @@ -/* -** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - -#define ldo_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" -#include "lzio.h" - - - -#define errorstatus(s) ((s) > LUA_YIELD) - - -/* -** {====================================================== -** Error-recovery functions -** ======================================================= -*/ - -/* -** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By -** default, Lua handles errors with exceptions when compiling as -** C++ code, with _longjmp/_setjmp when asked to use them, and with -** longjmp/setjmp otherwise. -*/ -#if !defined(LUAI_THROW) /* { */ - -#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ - -/* C++ exceptions */ -#define LUAI_THROW(L,c) throw(c) -#define LUAI_TRY(L,c,a) \ - try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } -#define luai_jmpbuf int /* dummy variable */ - -#elif defined(LUA_USE_POSIX) /* }{ */ - -/* in POSIX, try _longjmp/_setjmp (more efficient) */ -#define LUAI_THROW(L,c) _longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#else /* }{ */ - -/* ISO C handling with long jumps */ -#define LUAI_THROW(L,c) longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#endif /* } */ - -#endif /* } */ - - - -/* chain list of long jump buffers */ -struct lua_longjmp { - struct lua_longjmp *previous; - luai_jmpbuf b; - volatile int status; /* error code */ -}; - - -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { - switch (errcode) { - case LUA_ERRMEM: { /* memory error? */ - setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ - break; - } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } - default: { - setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ - break; - } - } - L->top = oldtop + 1; -} - - -l_noret luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { /* thread has an error handler? */ - L->errorJmp->status = errcode; /* set status */ - LUAI_THROW(L, L->errorJmp); /* jump to it */ - } - else { /* thread has no error handler */ - global_State *g = G(L); - L->status = cast_byte(errcode); /* mark it as dead */ - if (g->mainthread->errorJmp) { /* main thread has a handler? */ - setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ - luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ - } - else { /* no handler at all; abort */ - if (g->panic) { /* panic function? */ - seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (L->ci->top < L->top) - L->ci->top = L->top; /* pushing msg. can break this invariant */ - lua_unlock(L); - g->panic(L); /* call panic function (last chance to jump out) */ - } - abort(); - } - } -} - - -int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = L->nCcalls; - struct lua_longjmp lj; - lj.status = LUA_OK; - lj.previous = L->errorJmp; /* chain new error handler */ - L->errorJmp = &lj; - LUAI_TRY(L, &lj, - (*f)(L, ud); - ); - L->errorJmp = lj.previous; /* restore old error handler */ - L->nCcalls = oldnCcalls; - return lj.status; -} - -/* }====================================================== */ - - -/* -** {================================================================== -** Stack reallocation -** =================================================================== -*/ -static void correctstack (lua_State *L, TValue *oldstack) { - CallInfo *ci; - UpVal *up; - L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->u.open.next) - up->v = (up->v - oldstack) + L->stack; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - ci->top = (ci->top - oldstack) + L->stack; - ci->func = (ci->func - oldstack) + L->stack; - if (isLua(ci)) - ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; - } -} - - -/* some space for error handling */ -#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) - - -void luaD_reallocstack (lua_State *L, int newsize) { - TValue *oldstack = L->stack; - int lim = L->stacksize; - lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); - for (; lim < newsize; lim++) - setnilvalue(L->stack + lim); /* erase new segment */ - L->stacksize = newsize; - L->stack_last = L->stack + newsize - EXTRA_STACK; - correctstack(L, oldstack); -} - - -void luaD_growstack (lua_State *L, int n) { - int size = L->stacksize; - if (size > LUAI_MAXSTACK) /* error after extra size? */ - luaD_throw(L, LUA_ERRERR); - else { - int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; - int newsize = 2 * size; - if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; - if (newsize < needed) newsize = needed; - if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ - luaD_reallocstack(L, ERRORSTACKSIZE); - luaG_runerror(L, "stack overflow"); - } - else - luaD_reallocstack(L, newsize); - } -} - - -static int stackinuse (lua_State *L) { - CallInfo *ci; - StkId lim = L->top; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - if (lim < ci->top) lim = ci->top; - } - lua_assert(lim <= L->stack_last); - return cast_int(lim - L->stack) + 1; /* part of stack in use */ -} - - -void luaD_shrinkstack (lua_State *L) { - int inuse = stackinuse(L); - int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; - if (goodsize > LUAI_MAXSTACK) - goodsize = LUAI_MAXSTACK; /* respect stack limit */ - if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ - luaE_freeCI(L); /* free all CIs (list grew because of an error) */ - else - luaE_shrinkCI(L); /* shrink list */ - /* if thread is currently not handling a stack overflow and its - good size is smaller than current size, shrink its stack */ - if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && - goodsize < L->stacksize) - luaD_reallocstack(L, goodsize); - else /* don't change stack */ - condmovestack(L,{},{}); /* (change only for debugging) */ -} - - -void luaD_inctop (lua_State *L) { - luaD_checkstack(L, 1); - L->top++; -} - -/* }================================================================== */ - - -/* -** Call a hook for the given event. Make sure there is a hook to be -** called. (Both 'L->hook' and 'L->hookmask', which triggers this -** function, can be changed asynchronously by signals.) -*/ -void luaD_hook (lua_State *L, int event, int line) { - lua_Hook hook = L->hook; - if (hook && L->allowhook) { /* make sure there is a hook */ - CallInfo *ci = L->ci; - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, ci->top); - lua_Debug ar; - ar.event = event; - ar.currentline = line; - ar.i_ci = ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - L->allowhook = 0; /* cannot call hooks inside a hook */ - ci->callstatus |= CIST_HOOKED; - lua_unlock(L); - (*hook)(L, &ar); - lua_lock(L); - lua_assert(!L->allowhook); - L->allowhook = 1; - ci->top = restorestack(L, ci_top); - L->top = restorestack(L, top); - ci->callstatus &= ~CIST_HOOKED; - } -} - - -static void callhook (lua_State *L, CallInfo *ci) { - int hook = LUA_HOOKCALL; - ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ - if (isLua(ci->previous) && - GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { - ci->callstatus |= CIST_TAIL; - hook = LUA_HOOKTAILCALL; - } - luaD_hook(L, hook, -1); - ci->u.l.savedpc--; /* correct 'pc' */ -} - - -static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { - int i; - int nfixargs = p->numparams; - StkId base, fixed; - /* move fixed parameters to final position */ - fixed = L->top - actual; /* first fixed argument */ - base = L->top; /* final position of first argument */ - for (i = 0; i < nfixargs && i < actual; i++) { - setobjs2s(L, L->top++, fixed + i); - setnilvalue(fixed + i); /* erase original copy (for GC) */ - } - for (; i < nfixargs; i++) - setnilvalue(L->top++); /* complete missing arguments */ - return base; -} - - -/* -** Check whether __call metafield of 'func' is a function. If so, put -** it in stack below original 'func' so that 'luaD_precall' can call -** it. Raise an error if __call metafield is not a function. -*/ -static void tryfuncTM (lua_State *L, StkId func) { - const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); - StkId p; - if (!ttisfunction(tm)) - luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at 'func' */ - for (p = L->top; p > func; p--) - setobjs2s(L, p, p-1); - L->top++; /* slot ensured by caller */ - setobj2s(L, func, tm); /* tag method is the new function to be called */ -} - - -/* -** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. -** Handle most typical cases (zero results for commands, one result for -** expressions, multiple results for tail calls/single parameters) -** separated. -*/ -static int moveresults (lua_State *L, const TValue *firstResult, StkId res, - int nres, int wanted) { - switch (wanted) { /* handle typical cases separately */ - case 0: break; /* nothing to move */ - case 1: { /* one result needed */ - if (nres == 0) /* no results? */ - firstResult = luaO_nilobject; /* adjust with nil */ - setobjs2s(L, res, firstResult); /* move it to proper place */ - break; - } - case LUA_MULTRET: { - int i; - for (i = 0; i < nres; i++) /* move all results to correct place */ - setobjs2s(L, res + i, firstResult + i); - L->top = res + nres; - return 0; /* wanted == LUA_MULTRET */ - } - default: { - int i; - if (wanted <= nres) { /* enough results? */ - for (i = 0; i < wanted; i++) /* move wanted results to correct place */ - setobjs2s(L, res + i, firstResult + i); - } - else { /* not enough results; use all of them plus nils */ - for (i = 0; i < nres; i++) /* move all results to correct place */ - setobjs2s(L, res + i, firstResult + i); - for (; i < wanted; i++) /* complete wanted number of results */ - setnilvalue(res + i); - } - break; - } - } - L->top = res + wanted; /* top points after the last result */ - return 1; -} - - -/* -** Finishes a function call: calls hook if necessary, removes CallInfo, -** moves current number of results to proper place; returns 0 iff call -** wanted multiple (variable number of) results. -*/ -int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { - StkId res; - int wanted = ci->nresults; - if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { - if (L->hookmask & LUA_MASKRET) { - ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ - luaD_hook(L, LUA_HOOKRET, -1); - firstResult = restorestack(L, fr); - } - L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ - } - res = ci->func; /* res == final position of 1st result */ - L->ci = ci->previous; /* back to caller */ - /* move results to proper place */ - return moveresults(L, firstResult, res, nres, wanted); -} - - - -#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) - - -/* macro to check stack size, preserving 'p' */ -#define checkstackp(L,n,p) \ - luaD_checkstackaux(L, n, \ - ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ - luaC_checkGC(L), /* stack grow uses memory */ \ - p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ - - -/* -** Prepares a function call: checks the stack, creates a new CallInfo -** entry, fills in the relevant information, calls hook if needed. -** If function is a C function, does the call, too. (Otherwise, leave -** the execution ('luaV_execute') to the caller, to allow stackless -** calls.) Returns true iff function has been executed (C function). -*/ -int luaD_precall (lua_State *L, StkId func, int nresults) { - lua_CFunction f; - CallInfo *ci; - switch (ttype(func)) { - case LUA_TCCL: /* C closure */ - f = clCvalue(func)->f; - goto Cfunc; - case LUA_TLCF: /* light C function */ - f = fvalue(func); - Cfunc: { - int n; /* number of returns */ - checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = func; - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = (*f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, ci, L->top - n, n); - return 1; - } - case LUA_TLCL: { /* Lua function: prepare its call */ - StkId base; - Proto *p = clLvalue(func)->p; - int n = cast_int(L->top - func) - 1; /* number of real arguments */ - int fsize = p->maxstacksize; /* frame size */ - checkstackp(L, fsize, func); - if (p->is_vararg) - base = adjust_varargs(L, p, n); - else { /* non vararg function */ - for (; n < p->numparams; n++) - setnilvalue(L->top++); /* complete missing arguments */ - base = func + 1; - } - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = func; - ci->u.l.base = base; - L->top = ci->top = base + fsize; - lua_assert(ci->top <= L->stack_last); - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_LUA; - if (L->hookmask & LUA_MASKCALL) - callhook(L, ci); - return 0; - } - default: { /* not a function */ - checkstackp(L, 1, func); /* ensure space for metamethod */ - tryfuncTM(L, func); /* try to get '__call' metamethod */ - return luaD_precall(L, func, nresults); /* now it must be a function */ - } - } -} - - -/* -** Check appropriate error for stack overflow ("regular" overflow or -** overflow while handling stack overflow). If 'nCalls' is larger than -** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but -** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to -** allow overflow handling to work) -*/ -static void stackerror (lua_State *L) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ -} - - -/* -** Call a function (C or Lua). The function to be called is at *func. -** The arguments are on the stack, right after the function. -** When returns, all the results are on the stack, starting at the original -** function position. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUAI_MAXCCALLS) - stackerror(L); - if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ - luaV_execute(L); /* call it */ - L->nCcalls--; -} - - -/* -** Similar to 'luaD_call', but does not allow yields during the call -*/ -void luaD_callnoyield (lua_State *L, StkId func, int nResults) { - L->nny++; - luaD_call(L, func, nResults); - L->nny--; -} - - -/* -** Completes the execution of an interrupted C function, calling its -** continuation function. -*/ -static void finishCcall (lua_State *L, int status) { - CallInfo *ci = L->ci; - int n; - /* must have a continuation and must be able to call it */ - lua_assert(ci->u.c.k != NULL && L->nny == 0); - /* error status can only happen in a protected call */ - lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); - if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ - ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ - L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ - } - /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already - handled */ - adjustresults(L, ci->nresults); - lua_unlock(L); - n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ -} - - -/* -** Executes "full continuation" (everything in the stack) of a -** previously interrupted coroutine until the stack is empty (or another -** interruption long-jumps out of the loop). If the coroutine is -** recovering from an error, 'ud' points to the error status, which must -** be passed to the first continuation function (otherwise the default -** status is LUA_YIELD). -*/ -static void unroll (lua_State *L, void *ud) { - if (ud != NULL) /* error status? */ - finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ - while (L->ci != &L->base_ci) { /* something in the stack */ - if (!isLua(L->ci)) /* C function? */ - finishCcall(L, LUA_YIELD); /* complete its execution */ - else { /* Lua function */ - luaV_finishOp(L); /* finish interrupted instruction */ - luaV_execute(L); /* execute down to higher C 'boundary' */ - } - } -} - - -/* -** Try to find a suspended protected call (a "recover point") for the -** given thread. -*/ -static CallInfo *findpcall (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ - if (ci->callstatus & CIST_YPCALL) - return ci; - } - return NULL; /* no pending pcall */ -} - - -/* -** Recovers from an error in a coroutine. Finds a recover point (if -** there is one) and completes the execution of the interrupted -** 'luaD_pcall'. If there is no recover point, returns zero. -*/ -static int recover (lua_State *L, int status) { - StkId oldtop; - CallInfo *ci = findpcall(L); - if (ci == NULL) return 0; /* no recovery point */ - /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->extra); - luaF_close(L, oldtop); - seterrorobj(L, status, oldtop); - L->ci = ci; - L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ - L->nny = 0; /* should be zero to be yieldable */ - luaD_shrinkstack(L); - L->errfunc = ci->u.c.old_errfunc; - return 1; /* continue running the coroutine */ -} - - -/* -** Signal an error in the call to 'lua_resume', not in the execution -** of the coroutine itself. (Such errors should not be handled by any -** coroutine error handler and should not kill the coroutine.) -*/ -static int resume_error (lua_State *L, const char *msg, int narg) { - L->top -= narg; /* remove args from the stack */ - setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ - api_incr_top(L); - lua_unlock(L); - return LUA_ERRRUN; -} - - -/* -** Do the work for 'lua_resume' in protected mode. Most of the work -** depends on the status of the coroutine: initial state, suspended -** inside a hook, or regularly suspended (optionally with a continuation -** function), plus erroneous cases: non-suspended coroutine or dead -** coroutine. -*/ -static void resume (lua_State *L, void *ud) { - int n = *(cast(int*, ud)); /* number of arguments */ - StkId firstArg = L->top - n; /* first argument */ - CallInfo *ci = L->ci; - if (L->status == LUA_OK) { /* starting a coroutine? */ - if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ - luaV_execute(L); /* call it */ - } - else { /* resuming from previous yield */ - lua_assert(L->status == LUA_YIELD); - L->status = LUA_OK; /* mark that it is running (again) */ - ci->func = restorestack(L, ci->extra); - if (isLua(ci)) /* yielded inside a hook? */ - luaV_execute(L); /* just continue running Lua code */ - else { /* 'common' yield */ - if (ci->u.c.k != NULL) { /* does it have a continuation function? */ - lua_unlock(L); - n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ - lua_lock(L); - api_checknelems(L, n); - firstArg = L->top - n; /* yield results come from continuation */ - } - luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ - } - unroll(L, NULL); /* run continuation */ - } -} - - -LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { - int status; - unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ - lua_lock(L); - if (L->status == LUA_OK) { /* may be starting a coroutine */ - if (L->ci != &L->base_ci) /* not in base level? */ - return resume_error(L, "cannot resume non-suspended coroutine", nargs); - } - else if (L->status != LUA_YIELD) - return resume_error(L, "cannot resume dead coroutine", nargs); - L->nCcalls = (from) ? from->nCcalls + 1 : 1; - if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow", nargs); - luai_userstateresume(L, nargs); - L->nny = 0; /* allow yields */ - api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); - status = luaD_rawrunprotected(L, resume, &nargs); - if (status == -1) /* error calling 'lua_resume'? */ - status = LUA_ERRRUN; - else { /* continue running after recoverable errors */ - while (errorstatus(status) && recover(L, status)) { - /* unroll continuation */ - status = luaD_rawrunprotected(L, unroll, &status); - } - if (errorstatus(status)) { /* unrecoverable error? */ - L->status = cast_byte(status); /* mark thread as 'dead' */ - seterrorobj(L, status, L->top); /* push error message */ - L->ci->top = L->top; - } - else lua_assert(status == L->status); /* normal end or yield */ - } - L->nny = oldnny; /* restore 'nny' */ - L->nCcalls--; - lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); - lua_unlock(L); - return status; -} - - -LUA_API int lua_isyieldable (lua_State *L) { - return (L->nny == 0); -} - - -LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k) { - CallInfo *ci = L->ci; - luai_userstateyield(L, nresults); - lua_lock(L); - api_checknelems(L, nresults); - if (L->nny > 0) { - if (L != G(L)->mainthread) - luaG_runerror(L, "attempt to yield across a C-call boundary"); - else - luaG_runerror(L, "attempt to yield from outside a coroutine"); - } - L->status = LUA_YIELD; - ci->extra = savestack(L, ci->func); /* save current 'func' */ - if (isLua(ci)) { /* inside a hook? */ - api_check(L, k == NULL, "hooks cannot continue after yielding"); - } - else { - if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ - ci->u.c.ctx = ctx; /* save context */ - ci->func = L->top - nresults - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); - } - lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ - lua_unlock(L); - return 0; /* return to 'luaD_hook' */ -} - - -int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t old_top, ptrdiff_t ef) { - int status; - CallInfo *old_ci = L->ci; - lu_byte old_allowhooks = L->allowhook; - unsigned short old_nny = L->nny; - ptrdiff_t old_errfunc = L->errfunc; - L->errfunc = ef; - status = luaD_rawrunprotected(L, func, u); - if (status != LUA_OK) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close possible pending closures */ - seterrorobj(L, status, oldtop); - L->ci = old_ci; - L->allowhook = old_allowhooks; - L->nny = old_nny; - luaD_shrinkstack(L); - } - L->errfunc = old_errfunc; - return status; -} - - - -/* -** Execute a protected parser. -*/ -struct SParser { /* data to 'f_parser' */ - ZIO *z; - Mbuffer buff; /* dynamic structure used by the scanner */ - Dyndata dyd; /* dynamic structures used by the parser */ - const char *mode; - const char *name; -}; - - -static void checkmode (lua_State *L, const char *mode, const char *x) { - if (mode && strchr(mode, x[0]) == NULL) { - luaO_pushfstring(L, - "attempt to load a %s chunk (mode is '%s')", x, mode); - luaD_throw(L, LUA_ERRSYNTAX); - } -} - - -static void f_parser (lua_State *L, void *ud) { - LClosure *cl; - struct SParser *p = cast(struct SParser *, ud); - int c = zgetc(p->z); /* read first character */ - if (c == LUA_SIGNATURE[0]) { - checkmode(L, p->mode, "binary"); - cl = luaU_undump(L, p->z, p->name); - } - else { - checkmode(L, p->mode, "text"); - cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); - } - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luaF_initupvals(L, cl); -} - - -int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, - const char *mode) { - struct SParser p; - int status; - L->nny++; /* cannot yield during parsing */ - p.z = z; p.name = name; p.mode = mode; - p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; - p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; - p.dyd.label.arr = NULL; p.dyd.label.size = 0; - luaZ_initbuffer(L, &p.buff); - status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); - luaZ_freebuffer(L, &p.buff); - luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); - luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); - luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); - L->nny--; - return status; -} - - +/* +** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + +#define errorstatus(s) ((s) > LUA_YIELD) + + +/* +** {====================================================== +** Error-recovery functions +** ======================================================= +*/ + +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ + +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else /* }{ */ + +/* ISO C handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif /* } */ + +#endif /* } */ + + + +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + luai_jmpbuf b; + volatile int status; /* error code */ +}; + + +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + default: { + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ + break; + } + } + L->top = oldtop + 1; +} + + +l_noret luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ + } + else { /* thread has no error handler */ + global_State *g = G(L); + L->status = cast_byte(errcode); /* mark it as dead */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (g->panic) { /* panic function? */ + seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ + lua_unlock(L); + g->panic(L); /* call panic function (last chance to jump out) */ + } + abort(); + } + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + unsigned short oldnCcalls = L->nCcalls; + struct lua_longjmp lj; + lj.status = LUA_OK; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + LUAI_TRY(L, &lj, + (*f)(L, ud); + ); + L->errorJmp = lj.previous; /* restore old error handler */ + L->nCcalls = oldnCcalls; + return lj.status; +} + +/* }====================================================== */ + + +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ +static void correctstack (lua_State *L, TValue *oldstack) { + CallInfo *ci; + UpVal *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v = (up->v - oldstack) + L->stack; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top = (ci->top - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; + } +} + + +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + + +void luaD_reallocstack (lua_State *L, int newsize) { + TValue *oldstack = L->stack; + int lim = L->stacksize; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); + for (; lim < newsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ + L->stacksize = newsize; + L->stack_last = L->stack + newsize - EXTRA_STACK; + correctstack(L, oldstack); +} + + +void luaD_growstack (lua_State *L, int n) { + int size = L->stacksize; + if (size > LUAI_MAXSTACK) /* error after extra size? */ + luaD_throw(L, LUA_ERRERR); + else { + int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; + int newsize = 2 * size; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } +} + + +static int stackinuse (lua_State *L) { + CallInfo *ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + if (lim < ci->top) lim = ci->top; + } + lua_assert(lim <= L->stack_last); + return cast_int(lim - L->stack) + 1; /* part of stack in use */ +} + + +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; + if (goodsize > LUAI_MAXSTACK) + goodsize = LUAI_MAXSTACK; /* respect stack limit */ + if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ + else + luaE_shrinkCI(L); /* shrink list */ + /* if thread is currently not handling a stack overflow and its + good size is smaller than current size, shrink its stack */ + if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && + goodsize < L->stacksize) + luaD_reallocstack(L, goodsize); + else /* don't change stack */ + condmovestack(L,{},{}); /* (change only for debugging) */ +} + + +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top++; +} + +/* }================================================================== */ + + +/* +** Call a hook for the given event. Make sure there is a hook to be +** called. (Both 'L->hook' and 'L->hookmask', which triggers this +** function, can be changed asynchronously by signals.) +*/ +void luaD_hook (lua_State *L, int event, int line) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { /* make sure there is a hook */ + CallInfo *ci = L->ci; + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, ci->top); + lua_Debug ar; + ar.event = event; + ar.currentline = line; + ar.i_ci = ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= CIST_HOOKED; + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); + ci->callstatus &= ~CIST_HOOKED; + } +} + + +static void callhook (lua_State *L, CallInfo *ci) { + int hook = LUA_HOOKCALL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { + ci->callstatus |= CIST_TAIL; + hook = LUA_HOOKTAILCALL; + } + luaD_hook(L, hook, -1); + ci->u.l.savedpc--; /* correct 'pc' */ +} + + +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { + int i; + int nfixargs = p->numparams; + StkId base, fixed; + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i = 0; i < nfixargs && i < actual; i++) { + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); /* erase original copy (for GC) */ + } + for (; i < nfixargs; i++) + setnilvalue(L->top++); /* complete missing arguments */ + return base; +} + + +/* +** Check whether __call metafield of 'func' is a function. If so, put +** it in stack below original 'func' so that 'luaD_precall' can call +** it. Raise an error if __call metafield is not a function. +*/ +static void tryfuncTM (lua_State *L, StkId func) { + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at 'func' */ + for (p = L->top; p > func; p--) + setobjs2s(L, p, p-1); + L->top++; /* slot ensured by caller */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ +} + + +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +static int moveresults (lua_State *L, const TValue *firstResult, StkId res, + int nres, int wanted) { + switch (wanted) { /* handle typical cases separately */ + case 0: break; /* nothing to move */ + case 1: { /* one result needed */ + if (nres == 0) /* no results? */ + firstResult = luaO_nilobject; /* adjust with nil */ + setobjs2s(L, res, firstResult); /* move it to proper place */ + break; + } + case LUA_MULTRET: { + int i; + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + L->top = res + nres; + return 0; /* wanted == LUA_MULTRET */ + } + default: { + int i; + if (wanted <= nres) { /* enough results? */ + for (i = 0; i < wanted; i++) /* move wanted results to correct place */ + setobjs2s(L, res + i, firstResult + i); + } + else { /* not enough results; use all of them plus nils */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(res + i); + } + break; + } + } + L->top = res + wanted; /* top points after the last result */ + return 1; +} + + +/* +** Finishes a function call: calls hook if necessary, removes CallInfo, +** moves current number of results to proper place; returns 0 iff call +** wanted multiple (variable number of) results. +*/ +int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { + StkId res; + int wanted = ci->nresults; + if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { + if (L->hookmask & LUA_MASKRET) { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + luaD_hook(L, LUA_HOOKRET, -1); + firstResult = restorestack(L, fr); + } + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ + } + res = ci->func; /* res == final position of 1st result */ + L->ci = ci->previous; /* back to caller */ + /* move results to proper place */ + return moveresults(L, firstResult, res, nres, wanted); +} + + + +#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) + + +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ + luaC_checkGC(L), /* stack grow uses memory */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + +/* +** Prepares a function call: checks the stack, creates a new CallInfo +** entry, fills in the relevant information, calls hook if needed. +** If function is a C function, does the call, too. (Otherwise, leave +** the execution ('luaV_execute') to the caller, to allow stackless +** calls.) Returns true iff function has been executed (C function). +*/ +int luaD_precall (lua_State *L, StkId func, int nresults) { + lua_CFunction f; + CallInfo *ci; + switch (ttype(func)) { + case LUA_TCCL: /* C closure */ + f = clCvalue(func)->f; + goto Cfunc; + case LUA_TLCF: /* light C function */ + f = fvalue(func); + Cfunc: { + int n; /* number of returns */ + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); + return 1; + } + case LUA_TLCL: { /* Lua function: prepare its call */ + StkId base; + Proto *p = clLvalue(func)->p; + int n = cast_int(L->top - func) - 1; /* number of real arguments */ + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); + if (p->is_vararg) + base = adjust_varargs(L, p, n); + else { /* non vararg function */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ + base = func + 1; + } + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->u.l.base = base; + L->top = ci->top = base + fsize; + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; + } + default: { /* not a function */ + checkstackp(L, 1, func); /* ensure space for metamethod */ + tryfuncTM(L, func); /* try to get '__call' metamethod */ + return luaD_precall(L, func, nresults); /* now it must be a function */ + } + } +} + + +/* +** Check appropriate error for stack overflow ("regular" overflow or +** overflow while handling stack overflow). If 'nCalls' is larger than +** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but +** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to +** allow overflow handling to work) +*/ +static void stackerror (lua_State *L) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ +} + + +/* +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) + stackerror(L); + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + L->nCcalls--; +} + + +/* +** Similar to 'luaD_call', but does not allow yields during the call +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + L->nny++; + luaD_call(L, func, nResults); + L->nny--; +} + + +/* +** Completes the execution of an interrupted C function, calling its +** continuation function. +*/ +static void finishCcall (lua_State *L, int status) { + CallInfo *ci = L->ci; + int n; + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && L->nny == 0); + /* error status can only happen in a protected call */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ + L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ + } + /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already + handled */ + adjustresults(L, ci->nresults); + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ +} + + +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). If the coroutine is +** recovering from an error, 'ud' points to the error status, which must +** be passed to the first continuation function (otherwise the default +** status is LUA_YIELD). +*/ +static void unroll (lua_State *L, void *ud) { + if (ud != NULL) /* error status? */ + finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + while (L->ci != &L->base_ci) { /* something in the stack */ + if (!isLua(L->ci)) /* C function? */ + finishCcall(L, LUA_YIELD); /* complete its execution */ + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ + } + } +} + + +/* +** Try to find a suspended protected call (a "recover point") for the +** given thread. +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +/* +** Recovers from an error in a coroutine. Finds a recover point (if +** there is one) and completes the execution of the interrupted +** 'luaD_pcall'. If there is no recover point, returns zero. +*/ +static int recover (lua_State *L, int status) { + StkId oldtop; + CallInfo *ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ + /* "finish" luaD_pcall */ + oldtop = restorestack(L, ci->extra); + luaF_close(L, oldtop); + seterrorobj(L, status, oldtop); + L->ci = ci; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ + L->nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); + L->errfunc = ci->u.c.old_errfunc; + return 1; /* continue running the coroutine */ +} + + +/* +** Signal an error in the call to 'lua_resume', not in the execution +** of the coroutine itself. (Such errors should not be handled by any +** coroutine error handler and should not kill the coroutine.) +*/ +static int resume_error (lua_State *L, const char *msg, int narg) { + L->top -= narg; /* remove args from the stack */ + setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ + api_incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + +/* +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. +*/ +static void resume (lua_State *L, void *ud) { + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top - n; /* first argument */ + CallInfo *ci = L->ci; + if (L->status == LUA_OK) { /* starting a coroutine? */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ + } + else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = LUA_OK; /* mark that it is running (again) */ + ci->func = restorestack(L, ci->extra); + if (isLua(ci)) /* yielded inside a hook? */ + luaV_execute(L); /* just continue running Lua code */ + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ + lua_unlock(L); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + firstArg = L->top - n; /* yield results come from continuation */ + } + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ + } + unroll(L, NULL); /* run continuation */ + } +} + + +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { + int status; + unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ + lua_lock(L); + if (L->status == LUA_OK) { /* may be starting a coroutine */ + if (L->ci != &L->base_ci) /* not in base level? */ + return resume_error(L, "cannot resume non-suspended coroutine", nargs); + } + else if (L->status != LUA_YIELD) + return resume_error(L, "cannot resume dead coroutine", nargs); + L->nCcalls = (from) ? from->nCcalls + 1 : 1; + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + luai_userstateresume(L, nargs); + L->nny = 0; /* allow yields */ + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); + status = luaD_rawrunprotected(L, resume, &nargs); + if (status == -1) /* error calling 'lua_resume'? */ + status = LUA_ERRRUN; + else { /* continue running after recoverable errors */ + while (errorstatus(status) && recover(L, status)) { + /* unroll continuation */ + status = luaD_rawrunprotected(L, unroll, &status); + } + if (errorstatus(status)) { /* unrecoverable error? */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + seterrorobj(L, status, L->top); /* push error message */ + L->ci->top = L->top; + } + else lua_assert(status == L->status); /* normal end or yield */ + } + L->nny = oldnny; /* restore 'nny' */ + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); + lua_unlock(L); + return status; +} + + +LUA_API int lua_isyieldable (lua_State *L) { + return (L->nny == 0); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { + CallInfo *ci = L->ci; + luai_userstateyield(L, nresults); + lua_lock(L); + api_checknelems(L, nresults); + if (L->nny > 0) { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across a C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } + L->status = LUA_YIELD; + ci->extra = savestack(L, ci->func); /* save current 'func' */ + if (isLua(ci)) { /* inside a hook? */ + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->func = L->top - nresults - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ + lua_unlock(L); + return 0; /* return to 'luaD_hook' */ +} + + +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != LUA_OK) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; + L->allowhook = old_allowhooks; + L->nny = old_nny; + luaD_shrinkstack(L); + } + L->errfunc = old_errfunc; + return status; +} + + + +/* +** Execute a protected parser. +*/ +struct SParser { /* data to 'f_parser' */ + ZIO *z; + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ + const char *mode; + const char *name; +}; + + +static void checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + luaO_pushfstring(L, + "attempt to load a %s chunk (mode is '%s')", x, mode); + luaD_throw(L, LUA_ERRSYNTAX); + } +} + + +static void f_parser (lua_State *L, void *ud) { + LClosure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = zgetc(p->z); /* read first character */ + if (c == LUA_SIGNATURE[0]) { + checkmode(L, p->mode, "binary"); + cl = luaU_undump(L, p->z, p->name); + } + else { + checkmode(L, p->mode, "text"); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); +} + + +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, + const char *mode) { + struct SParser p; + int status; + L->nny++; /* cannot yield during parsing */ + p.z = z; p.name = name; p.mode = mode; + p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; p.dyd.label.size = 0; + luaZ_initbuffer(L, &p.buff); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); + L->nny--; + return status; +} + + diff --git a/libs/lua/source/ldump.c b/libs/lua/source/ldump.c index f025acac..aba53880 100644 --- a/libs/lua/source/ldump.c +++ b/libs/lua/source/ldump.c @@ -1,215 +1,215 @@ -/* -** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ -** save precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#define ldump_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lobject.h" -#include "lstate.h" -#include "lundump.h" - - -typedef struct { - lua_State *L; - lua_Writer writer; - void *data; - int strip; - int status; -} DumpState; - - -/* -** All high-level dumps go through DumpVector; you can change it to -** change the endianness of the result -*/ -#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) - -#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) - - -static void DumpBlock (const void *b, size_t size, DumpState *D) { - if (D->status == 0 && size > 0) { - lua_unlock(D->L); - D->status = (*D->writer)(D->L, b, size, D->data); - lua_lock(D->L); - } -} - - -#define DumpVar(x,D) DumpVector(&x,1,D) - - -static void DumpByte (int y, DumpState *D) { - lu_byte x = (lu_byte)y; - DumpVar(x, D); -} - - -static void DumpInt (int x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpNumber (lua_Number x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpInteger (lua_Integer x, DumpState *D) { - DumpVar(x, D); -} - - -static void DumpString (const TString *s, DumpState *D) { - if (s == NULL) - DumpByte(0, D); - else { - size_t size = tsslen(s) + 1; /* include trailing '\0' */ - const char *str = getstr(s); - if (size < 0xFF) - DumpByte(cast_int(size), D); - else { - DumpByte(0xFF, D); - DumpVar(size, D); - } - DumpVector(str, size - 1, D); /* no need to save '\0' */ - } -} - - -static void DumpCode (const Proto *f, DumpState *D) { - DumpInt(f->sizecode, D); - DumpVector(f->code, f->sizecode, D); -} - - -static void DumpFunction(const Proto *f, TString *psource, DumpState *D); - -static void DumpConstants (const Proto *f, DumpState *D) { - int i; - int n = f->sizek; - DumpInt(n, D); - for (i = 0; i < n; i++) { - const TValue *o = &f->k[i]; - DumpByte(ttype(o), D); - switch (ttype(o)) { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpByte(bvalue(o), D); - break; - case LUA_TNUMFLT: - DumpNumber(fltvalue(o), D); - break; - case LUA_TNUMINT: - DumpInteger(ivalue(o), D); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - DumpString(tsvalue(o), D); - break; - default: - lua_assert(0); - } - } -} - - -static void DumpProtos (const Proto *f, DumpState *D) { - int i; - int n = f->sizep; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpFunction(f->p[i], f->source, D); -} - - -static void DumpUpvalues (const Proto *f, DumpState *D) { - int i, n = f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpByte(f->upvalues[i].instack, D); - DumpByte(f->upvalues[i].idx, D); - } -} - - -static void DumpDebug (const Proto *f, DumpState *D) { - int i, n; - n = (D->strip) ? 0 : f->sizelineinfo; - DumpInt(n, D); - DumpVector(f->lineinfo, n, D); - n = (D->strip) ? 0 : f->sizelocvars; - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpString(f->locvars[i].varname, D); - DumpInt(f->locvars[i].startpc, D); - DumpInt(f->locvars[i].endpc, D); - } - n = (D->strip) ? 0 : f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpString(f->upvalues[i].name, D); -} - - -static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { - if (D->strip || f->source == psource) - DumpString(NULL, D); /* no debug info or same source as its parent */ - else - DumpString(f->source, D); - DumpInt(f->linedefined, D); - DumpInt(f->lastlinedefined, D); - DumpByte(f->numparams, D); - DumpByte(f->is_vararg, D); - DumpByte(f->maxstacksize, D); - DumpCode(f, D); - DumpConstants(f, D); - DumpUpvalues(f, D); - DumpProtos(f, D); - DumpDebug(f, D); -} - - -static void DumpHeader (DumpState *D) { - DumpLiteral(LUA_SIGNATURE, D); - DumpByte(LUAC_VERSION, D); - DumpByte(LUAC_FORMAT, D); - DumpLiteral(LUAC_DATA, D); - DumpByte(sizeof(int), D); - DumpByte(sizeof(size_t), D); - DumpByte(sizeof(Instruction), D); - DumpByte(sizeof(lua_Integer), D); - DumpByte(sizeof(lua_Number), D); - DumpInteger(LUAC_INT, D); - DumpNumber(LUAC_NUM, D); -} - - -/* -** dump Lua function as precompiled chunk -*/ -int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, - int strip) { - DumpState D; - D.L = L; - D.writer = w; - D.data = data; - D.strip = strip; - D.status = 0; - DumpHeader(&D); - DumpByte(f->sizeupvalues, &D); - DumpFunction(f, NULL, &D); - return D.status; -} - +/* +** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ +** save precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define ldump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lobject.h" +#include "lstate.h" +#include "lundump.h" + + +typedef struct { + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; +} DumpState; + + +/* +** All high-level dumps go through DumpVector; you can change it to +** change the endianness of the result +*/ +#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) + +#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) + + +static void DumpBlock (const void *b, size_t size, DumpState *D) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } +} + + +#define DumpVar(x,D) DumpVector(&x,1,D) + + +static void DumpByte (int y, DumpState *D) { + lu_byte x = (lu_byte)y; + DumpVar(x, D); +} + + +static void DumpInt (int x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpNumber (lua_Number x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpInteger (lua_Integer x, DumpState *D) { + DumpVar(x, D); +} + + +static void DumpString (const TString *s, DumpState *D) { + if (s == NULL) + DumpByte(0, D); + else { + size_t size = tsslen(s) + 1; /* include trailing '\0' */ + const char *str = getstr(s); + if (size < 0xFF) + DumpByte(cast_int(size), D); + else { + DumpByte(0xFF, D); + DumpVar(size, D); + } + DumpVector(str, size - 1, D); /* no need to save '\0' */ + } +} + + +static void DumpCode (const Proto *f, DumpState *D) { + DumpInt(f->sizecode, D); + DumpVector(f->code, f->sizecode, D); +} + + +static void DumpFunction(const Proto *f, TString *psource, DumpState *D); + +static void DumpConstants (const Proto *f, DumpState *D) { + int i; + int n = f->sizek; + DumpInt(n, D); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + DumpByte(ttype(o), D); + switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: + lua_assert(0); + } + } +} + + +static void DumpProtos (const Proto *f, DumpState *D) { + int i; + int n = f->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], f->source, D); +} + + +static void DumpUpvalues (const Proto *f, DumpState *D) { + int i, n = f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpByte(f->upvalues[i].instack, D); + DumpByte(f->upvalues[i].idx, D); + } +} + + +static void DumpDebug (const Proto *f, DumpState *D) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + DumpInt(n, D); + DumpVector(f->lineinfo, n, D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); +} + + +static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { + if (D->strip || f->source == psource) + DumpString(NULL, D); /* no debug info or same source as its parent */ + else + DumpString(f->source, D); + DumpInt(f->linedefined, D); + DumpInt(f->lastlinedefined, D); + DumpByte(f->numparams, D); + DumpByte(f->is_vararg, D); + DumpByte(f->maxstacksize, D); + DumpCode(f, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpProtos(f, D); + DumpDebug(f, D); +} + + +static void DumpHeader (DumpState *D) { + DumpLiteral(LUA_SIGNATURE, D); + DumpByte(LUAC_VERSION, D); + DumpByte(LUAC_FORMAT, D); + DumpLiteral(LUAC_DATA, D); + DumpByte(sizeof(int), D); + DumpByte(sizeof(size_t), D); + DumpByte(sizeof(Instruction), D); + DumpByte(sizeof(lua_Integer), D); + DumpByte(sizeof(lua_Number), D); + DumpInteger(LUAC_INT, D); + DumpNumber(LUAC_NUM, D); +} + + +/* +** dump Lua function as precompiled chunk +*/ +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpByte(f->sizeupvalues, &D); + DumpFunction(f, NULL, &D); + return D.status; +} + diff --git a/libs/lua/source/lfunc.c b/libs/lua/source/lfunc.c index ccafbb8a..bb6c0308 100644 --- a/libs/lua/source/lfunc.c +++ b/libs/lua/source/lfunc.c @@ -1,151 +1,151 @@ -/* -** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - -#define lfunc_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - - -CClosure *luaF_newCclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); - CClosure *c = gco2ccl(o); - c->nupvalues = cast_byte(n); - return c; -} - - -LClosure *luaF_newLclosure (lua_State *L, int n) { - GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); - LClosure *c = gco2lcl(o); - c->p = NULL; - c->nupvalues = cast_byte(n); - while (n--) c->upvals[n] = NULL; - return c; -} - -/* -** fill a closure with new closed upvalues -*/ -void luaF_initupvals (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = luaM_new(L, UpVal); - uv->refcount = 1; - uv->v = &uv->u.value; /* make it closed */ - setnilvalue(uv->v); - cl->upvals[i] = uv; - } -} - - -UpVal *luaF_findupval (lua_State *L, StkId level) { - UpVal **pp = &L->openupval; - UpVal *p; - UpVal *uv; - lua_assert(isintwups(L) || L->openupval == NULL); - while (*pp != NULL && (p = *pp)->v >= level) { - lua_assert(upisopen(p)); - if (p->v == level) /* found a corresponding upvalue? */ - return p; /* return it */ - pp = &p->u.open.next; - } - /* not found: create a new upvalue */ - uv = luaM_new(L, UpVal); - uv->refcount = 0; - uv->u.open.next = *pp; /* link it to list of open upvalues */ - uv->u.open.touched = 1; - *pp = uv; - uv->v = level; /* current value lives in the stack */ - if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ - L->twups = G(L)->twups; /* link it to the list */ - G(L)->twups = L; - } - return uv; -} - - -void luaF_close (lua_State *L, StkId level) { - UpVal *uv; - while (L->openupval != NULL && (uv = L->openupval)->v >= level) { - lua_assert(upisopen(uv)); - L->openupval = uv->u.open.next; /* remove from 'open' list */ - if (uv->refcount == 0) /* no references? */ - luaM_free(L, uv); /* free upvalue */ - else { - setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ - uv->v = &uv->u.value; /* now current value lives here */ - luaC_upvalbarrier(L, uv); - } - } -} - - -Proto *luaF_newproto (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); - Proto *f = gco2p(o); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->cache = NULL; - f->sizecode = 0; - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->linedefined = 0; - f->lastlinedefined = 0; - f->source = NULL; - return f; -} - - -void luaF_freeproto (lua_State *L, Proto *f) { - luaM_freearray(L, f->code, f->sizecode); - luaM_freearray(L, f->p, f->sizep); - luaM_freearray(L, f->k, f->sizek); - luaM_freearray(L, f->lineinfo, f->sizelineinfo); - luaM_freearray(L, f->locvars, f->sizelocvars); - luaM_freearray(L, f->upvalues, f->sizeupvalues); - luaM_free(L, f); -} - - -/* -** Look for n-th local variable at line 'line' in function 'func'. -** Returns NULL if not found. -*/ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { - int i; - for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { - if (pc < f->locvars[i].endpc) { /* is variable active? */ - local_number--; - if (local_number == 0) - return getstr(f->locvars[i].varname); - } - } - return NULL; /* not found */ -} - +/* +** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#define lfunc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +CClosure *luaF_newCclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(n); + return c; +} + + +LClosure *luaF_newLclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(n); + while (n--) c->upvals[n] = NULL; + return c; +} + +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } +} + + +UpVal *luaF_findupval (lua_State *L, StkId level) { + UpVal **pp = &L->openupval; + UpVal *p; + UpVal *uv; + lua_assert(isintwups(L) || L->openupval == NULL); + while (*pp != NULL && (p = *pp)->v >= level) { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; + } + /* not found: create a new upvalue */ + uv = luaM_new(L, UpVal); + uv->refcount = 0; + uv->u.open.next = *pp; /* link it to list of open upvalues */ + uv->u.open.touched = 1; + *pp = uv; + uv->v = level; /* current value lives in the stack */ + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } + return uv; +} + + +void luaF_close (lua_State *L, StkId level) { + UpVal *uv; + while (L->openupval != NULL && (uv = L->openupval)->v >= level) { + lua_assert(upisopen(uv)); + L->openupval = uv->u.open.next; /* remove from 'open' list */ + if (uv->refcount == 0) /* no references? */ + luaM_free(L, uv); /* free upvalue */ + else { + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ + uv->v = &uv->u.value; /* now current value lives here */ + luaC_upvalbarrier(L, uv); + } + } +} + + +Proto *luaF_newproto (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); + Proto *f = gco2p(o); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->cache = NULL; + f->sizecode = 0; + f->lineinfo = NULL; + f->sizelineinfo = 0; + f->upvalues = NULL; + f->sizeupvalues = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->locvars = NULL; + f->sizelocvars = 0; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + + +void luaF_freeproto (lua_State *L, Proto *f) { + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); + luaM_free(L, f); +} + + +/* +** Look for n-th local variable at line 'line' in function 'func'. +** Returns NULL if not found. +*/ +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return getstr(f->locvars[i].varname); + } + } + return NULL; /* not found */ +} + diff --git a/libs/lua/source/lgc.c b/libs/lua/source/lgc.c index db4df829..4377f74c 100644 --- a/libs/lua/source/lgc.c +++ b/libs/lua/source/lgc.c @@ -1,1179 +1,1179 @@ -/* -** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - -#define lgc_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -/* -** internal state for collector while inside the atomic phase. The -** collector should never be in this state while running regular code. -*/ -#define GCSinsideatomic (GCSpause + 1) - -/* -** cost of sweeping one element (the size of a small object divided -** by some adjust for the sweep speed) -*/ -#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) - -/* maximum number of elements to sweep in each single step */ -#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) - -/* cost of calling one finalizer */ -#define GCFINALIZECOST GCSWEEPCOST - - -/* -** macro to adjust 'stepmul': 'stepmul' is actually used like -** 'stepmul / STEPMULADJ' (value chosen by tests) -*/ -#define STEPMULADJ 200 - - -/* -** macro to adjust 'pause': 'pause' is actually used like -** 'pause / PAUSEADJ' (value chosen by tests) -*/ -#define PAUSEADJ 100 - - -/* -** 'makewhite' erases all color bits then sets only the current white -** bit -*/ -#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) -#define makewhite(g,x) \ - (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) - -#define white2gray(x) resetbits(x->marked, WHITEBITS) -#define black2gray(x) resetbit(x->marked, BLACKBIT) - - -#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) - -#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) - - -#define checkconsistency(obj) \ - lua_longassert(!iscollectable(obj) || righttt(obj)) - - -#define markvalue(g,o) { checkconsistency(o); \ - if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } - -#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } - -/* -** mark an object that can be NULL (either because it is really optional, -** or it was stripped as debug info, or inside an uncompleted structure) -*/ -#define markobjectN(g,t) { if (t) markobject(g,t); } - -static void reallymarkobject (global_State *g, GCObject *o); - - -/* -** {====================================================== -** Generic functions -** ======================================================= -*/ - - -/* -** one after last element in a hash array -*/ -#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) - - -/* -** link collectable object 'o' into list pointed by 'p' -*/ -#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) - - -/* -** If key is not marked, mark its entry as dead. This allows key to be -** collected, but keeps its entry in the table. A dead node is needed -** when Lua looks up for a key (it may be part of a chain) and when -** traversing a weak table (key might be removed from the table during -** traversal). Other places never manipulate dead keys, because its -** associated nil value is enough to signal that the entry is logically -** empty. -*/ -static void removeentry (Node *n) { - lua_assert(ttisnil(gval(n))); - if (valiswhite(gkey(n))) - setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ -} - - -/* -** tells whether a key or value can be cleared from a weak -** table. Non-collectable objects are never removed from weak -** tables. Strings behave as 'values', so are never removed too. for -** other objects: if really collected, cannot keep them; for objects -** being finalized, keep them in keys, but not in values -*/ -static int iscleared (global_State *g, const TValue *o) { - if (!iscollectable(o)) return 0; - else if (ttisstring(o)) { - markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ - return 0; - } - else return iswhite(gcvalue(o)); -} - - -/* -** barrier that moves collector forward, that is, mark the white object -** being pointed by a black object. (If in sweep phase, clear the black -** object to white [sweep it] to avoid other barrier calls for this -** same object.) -*/ -void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { - global_State *g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - if (keepinvariant(g)) /* must keep invariant? */ - reallymarkobject(g, v); /* restore invariant */ - else { /* sweep phase */ - lua_assert(issweepphase(g)); - makewhite(g, o); /* mark main obj. as white to avoid other barriers */ - } -} - - -/* -** barrier that moves collector backward, that is, mark the black object -** pointing to a white object as gray again. -*/ -void luaC_barrierback_ (lua_State *L, Table *t) { - global_State *g = G(L); - lua_assert(isblack(t) && !isdead(g, t)); - black2gray(t); /* make table gray (again) */ - linkgclist(t, g->grayagain); -} - - -/* -** barrier for assignments to closed upvalues. Because upvalues are -** shared among closures, it is impossible to know the color of all -** closures pointing to it. So, we assume that the object being assigned -** must be marked. -*/ -void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = gcvalue(uv->v); - lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ - if (keepinvariant(g)) - markobject(g, o); -} - - -void luaC_fix (lua_State *L, GCObject *o) { - global_State *g = G(L); - lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ - white2gray(o); /* they will be gray forever */ - g->allgc = o->next; /* remove object from 'allgc' list */ - o->next = g->fixedgc; /* link it to 'fixedgc' list */ - g->fixedgc = o; -} - - -/* -** create a new collectable object (with given type and size) and link -** it to 'allgc' list. -*/ -GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { - global_State *g = G(L); - GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); - o->marked = luaC_white(g); - o->tt = tt; - o->next = g->allgc; - g->allgc = o; - return o; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Mark functions -** ======================================================= -*/ - - -/* -** mark an object. Userdata, strings, and closed upvalues are visited -** and turned black here. Other objects are marked gray and added -** to appropriate list to be visited (and turned black) later. (Open -** upvalues are already linked in 'headuv' list.) -*/ -static void reallymarkobject (global_State *g, GCObject *o) { - reentry: - white2gray(o); - switch (o->tt) { - case LUA_TSHRSTR: { - gray2black(o); - g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); - break; - } - case LUA_TLNGSTR: { - gray2black(o); - g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); - break; - } - case LUA_TUSERDATA: { - TValue uvalue; - markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ - gray2black(o); - g->GCmemtrav += sizeudata(gco2u(o)); - getuservalue(g->mainthread, gco2u(o), &uvalue); - if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ - o = gcvalue(&uvalue); - goto reentry; - } - break; - } - case LUA_TLCL: { - linkgclist(gco2lcl(o), g->gray); - break; - } - case LUA_TCCL: { - linkgclist(gco2ccl(o), g->gray); - break; - } - case LUA_TTABLE: { - linkgclist(gco2t(o), g->gray); - break; - } - case LUA_TTHREAD: { - linkgclist(gco2th(o), g->gray); - break; - } - case LUA_TPROTO: { - linkgclist(gco2p(o), g->gray); - break; - } - default: lua_assert(0); break; - } -} - - -/* -** mark metamethods for basic types -*/ -static void markmt (global_State *g) { - int i; - for (i=0; i < LUA_NUMTAGS; i++) - markobjectN(g, g->mt[i]); -} - - -/* -** mark all objects in list of being-finalized -*/ -static void markbeingfnz (global_State *g) { - GCObject *o; - for (o = g->tobefnz; o != NULL; o = o->next) - markobject(g, o); -} - - -/* -** Mark all values stored in marked open upvalues from non-marked threads. -** (Values from marked threads were already marked when traversing the -** thread.) Remove from the list threads that no longer have upvalues and -** not-marked threads. -*/ -static void remarkupvals (global_State *g) { - lua_State *thread; - lua_State **p = &g->twups; - while ((thread = *p) != NULL) { - lua_assert(!isblack(thread)); /* threads are never black */ - if (isgray(thread) && thread->openupval != NULL) - p = &thread->twups; /* keep marked thread with upvalues in the list */ - else { /* thread is not marked or without upvalues */ - UpVal *uv; - *p = thread->twups; /* remove thread from the list */ - thread->twups = thread; /* mark that it is out of list */ - for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { - if (uv->u.open.touched) { - markvalue(g, uv->v); /* remark upvalue's value */ - uv->u.open.touched = 0; - } - } - } - } -} - - -/* -** mark root set and reset all gray lists, to start a new collection -*/ -static void restartcollection (global_State *g) { - g->gray = g->grayagain = NULL; - g->weak = g->allweak = g->ephemeron = NULL; - markobject(g, g->mainthread); - markvalue(g, &g->l_registry); - markmt(g); - markbeingfnz(g); /* mark any finalizing object left from previous cycle */ -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Traverse functions -** ======================================================= -*/ - -/* -** Traverse a table with weak values and link it to proper list. During -** propagate phase, keep it in 'grayagain' list, to be revisited in the -** atomic phase. In the atomic phase, if table has any white value, -** put it in 'weak' list, to be cleared. -*/ -static void traverseweakvalue (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - /* if there is array part, assume it may have white values (it is not - worth traversing it now just to check) */ - int hasclears = (h->sizearray > 0); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ - hasclears = 1; /* table will have to be cleared */ - } - } - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasclears) - linkgclist(h, g->weak); /* has to be cleared later */ -} - - -/* -** Traverse an ephemeron table and link it to proper list. Returns true -** iff any object was marked during this traversal (which implies that -** convergence has to continue). During propagation phase, keep table -** in 'grayagain' list, to be visited again in the atomic phase. In -** the atomic phase, if table has any white->white entry, it has to -** be revisited during ephemeron convergence (as that key may turn -** black). Otherwise, if it has any white key, table has to be cleared -** (in the atomic phase). -*/ -static int traverseephemeron (global_State *g, Table *h) { - int marked = 0; /* true if an object is marked in this traversal */ - int hasclears = 0; /* true if table has white keys */ - int hasww = 0; /* true if table has entry "white-key -> white-value" */ - Node *n, *limit = gnodelast(h); - unsigned int i; - /* traverse array part */ - for (i = 0; i < h->sizearray; i++) { - if (valiswhite(&h->array[i])) { - marked = 1; - reallymarkobject(g, gcvalue(&h->array[i])); - } - } - /* traverse hash part */ - for (n = gnode(h, 0); n < limit; n++) { - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ - hasclears = 1; /* table must be cleared */ - if (valiswhite(gval(n))) /* value not marked yet? */ - hasww = 1; /* white-white entry */ - } - else if (valiswhite(gval(n))) { /* value not marked yet? */ - marked = 1; - reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ - } - } - /* link table into proper list */ - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasww) /* table has white->white entries? */ - linkgclist(h, g->ephemeron); /* have to propagate again */ - else if (hasclears) /* table has white keys? */ - linkgclist(h, g->allweak); /* may have to clean white keys */ - return marked; -} - - -static void traversestrongtable (global_State *g, Table *h) { - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) /* traverse array part */ - markvalue(g, &h->array[i]); - for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - checkdeadkey(n); - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ - else { - lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); /* mark key */ - markvalue(g, gval(n)); /* mark value */ - } - } -} - - -static lu_mem traversetable (global_State *g, Table *h) { - const char *weakkey, *weakvalue; - const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - markobjectN(g, h->metatable); - if (mode && ttisstring(mode) && /* is there a weak mode? */ - ((weakkey = strchr(svalue(mode), 'k')), - (weakvalue = strchr(svalue(mode), 'v')), - (weakkey || weakvalue))) { /* is really weak? */ - black2gray(h); /* keep table gray */ - if (!weakkey) /* strong keys? */ - traverseweakvalue(g, h); - else if (!weakvalue) /* strong values? */ - traverseephemeron(g, h); - else /* all weak */ - linkgclist(h, g->allweak); /* nothing to traverse now */ - } - else /* not weak */ - traversestrongtable(g, h); - return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * cast(size_t, allocsizenode(h)); -} - - -/* -** Traverse a prototype. (While a prototype is being build, its -** arrays can be larger than needed; the extra slots are filled with -** NULL, so the use of 'markobjectN') -*/ -static int traverseproto (global_State *g, Proto *f) { - int i; - if (f->cache && iswhite(f->cache)) - f->cache = NULL; /* allow cache to be collected */ - markobjectN(g, f->source); - for (i = 0; i < f->sizek; i++) /* mark literals */ - markvalue(g, &f->k[i]); - for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - markobjectN(g, f->upvalues[i].name); - for (i = 0; i < f->sizep; i++) /* mark nested protos */ - markobjectN(g, f->p[i]); - for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - markobjectN(g, f->locvars[i].varname); - return sizeof(Proto) + sizeof(Instruction) * f->sizecode + - sizeof(Proto *) * f->sizep + - sizeof(TValue) * f->sizek + - sizeof(int) * f->sizelineinfo + - sizeof(LocVar) * f->sizelocvars + - sizeof(Upvaldesc) * f->sizeupvalues; -} - - -static lu_mem traverseCclosure (global_State *g, CClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - markvalue(g, &cl->upvalue[i]); - return sizeCclosure(cl->nupvalues); -} - -/* -** open upvalues point to values in a thread, so those values should -** be marked when the thread is traversed except in the atomic phase -** (because then the value cannot be changed by the thread and the -** thread may not be traversed again) -*/ -static lu_mem traverseLclosure (global_State *g, LClosure *cl) { - int i; - markobjectN(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ - UpVal *uv = cl->upvals[i]; - if (uv != NULL) { - if (upisopen(uv) && g->gcstate != GCSinsideatomic) - uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ - else - markvalue(g, uv->v); - } - } - return sizeLclosure(cl->nupvalues); -} - - -static lu_mem traversethread (global_State *g, lua_State *th) { - StkId o = th->stack; - if (o == NULL) - return 1; /* stack not completely built yet */ - lua_assert(g->gcstate == GCSinsideatomic || - th->openupval == NULL || isintwups(th)); - for (; o < th->top; o++) /* mark live elements in the stack */ - markvalue(g, o); - if (g->gcstate == GCSinsideatomic) { /* final traversal? */ - StkId lim = th->stack + th->stacksize; /* real end of stack */ - for (; o < lim; o++) /* clear not-marked stack slice */ - setnilvalue(o); - /* 'remarkupvals' may have removed thread from 'twups' list */ - if (!isintwups(th) && th->openupval != NULL) { - th->twups = g->twups; /* link it back to the list */ - g->twups = th; - } - } - else if (g->gckind != KGC_EMERGENCY) - luaD_shrinkstack(th); /* do not change stack in emergency cycle */ - return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->nci); -} - - -/* -** traverse one gray object, turning it to black (except for threads, -** which are always gray). -*/ -static void propagatemark (global_State *g) { - lu_mem size; - GCObject *o = g->gray; - lua_assert(isgray(o)); - gray2black(o); - switch (o->tt) { - case LUA_TTABLE: { - Table *h = gco2t(o); - g->gray = h->gclist; /* remove from 'gray' list */ - size = traversetable(g, h); - break; - } - case LUA_TLCL: { - LClosure *cl = gco2lcl(o); - g->gray = cl->gclist; /* remove from 'gray' list */ - size = traverseLclosure(g, cl); - break; - } - case LUA_TCCL: { - CClosure *cl = gco2ccl(o); - g->gray = cl->gclist; /* remove from 'gray' list */ - size = traverseCclosure(g, cl); - break; - } - case LUA_TTHREAD: { - lua_State *th = gco2th(o); - g->gray = th->gclist; /* remove from 'gray' list */ - linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ - black2gray(o); - size = traversethread(g, th); - break; - } - case LUA_TPROTO: { - Proto *p = gco2p(o); - g->gray = p->gclist; /* remove from 'gray' list */ - size = traverseproto(g, p); - break; - } - default: lua_assert(0); return; - } - g->GCmemtrav += size; -} - - -static void propagateall (global_State *g) { - while (g->gray) propagatemark(g); -} - - -static void convergeephemerons (global_State *g) { - int changed; - do { - GCObject *w; - GCObject *next = g->ephemeron; /* get ephemeron list */ - g->ephemeron = NULL; /* tables may return to this list when traversed */ - changed = 0; - while ((w = next) != NULL) { - next = gco2t(w)->gclist; - if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ - propagateall(g); /* propagate changes */ - changed = 1; /* will have to revisit all ephemeron tables */ - } - } - } while (changed); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Sweep Functions -** ======================================================= -*/ - - -/* -** clear entries with unmarked keys from all weaktables in list 'l' up -** to element 'f' -*/ -static void clearkeys (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { - setnilvalue(gval(n)); /* remove value ... */ - } - if (ttisnil(gval(n))) /* is entry empty? */ - removeentry(n); /* remove entry from table */ - } - } -} - - -/* -** clear entries with unmarked values from all weaktables in list 'l' up -** to element 'f' -*/ -static void clearvalues (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { - Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); - unsigned int i; - for (i = 0; i < h->sizearray; i++) { - TValue *o = &h->array[i]; - if (iscleared(g, o)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { - setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* and remove entry from table */ - } - } - } -} - - -void luaC_upvdeccount (lua_State *L, UpVal *uv) { - lua_assert(uv->refcount > 0); - uv->refcount--; - if (uv->refcount == 0 && !upisopen(uv)) - luaM_free(L, uv); -} - - -static void freeLclosure (lua_State *L, LClosure *cl) { - int i; - for (i = 0; i < cl->nupvalues; i++) { - UpVal *uv = cl->upvals[i]; - if (uv) - luaC_upvdeccount(L, uv); - } - luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); -} - - -static void freeobj (lua_State *L, GCObject *o) { - switch (o->tt) { - case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; - case LUA_TLCL: { - freeLclosure(L, gco2lcl(o)); - break; - } - case LUA_TCCL: { - luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); - break; - } - case LUA_TTABLE: luaH_free(L, gco2t(o)); break; - case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; - case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; - case LUA_TSHRSTR: - luaS_remove(L, gco2ts(o)); /* remove it from hash table */ - luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); - break; - case LUA_TLNGSTR: { - luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); - break; - } - default: lua_assert(0); - } -} - - -#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); - - -/* -** sweep at most 'count' elements from a list of GCObjects erasing dead -** objects, where a dead object is one marked with the old (non current) -** white; change all non-dead objects back to white, preparing for next -** collection cycle. Return where to continue the traversal or NULL if -** list is finished. -*/ -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - global_State *g = G(L); - int ow = otherwhite(g); - int white = luaC_white(g); /* current white */ - while (*p != NULL && count-- > 0) { - GCObject *curr = *p; - int marked = curr->marked; - if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - *p = curr->next; /* remove 'curr' from list */ - freeobj(L, curr); /* erase 'curr' */ - } - else { /* change mark to 'white' */ - curr->marked = cast_byte((marked & maskcolors) | white); - p = &curr->next; /* go to next element */ - } - } - return (*p == NULL) ? NULL : p; -} - - -/* -** sweep a list until a live object (or end of list) -*/ -static GCObject **sweeptolive (lua_State *L, GCObject **p) { - GCObject **old = p; - do { - p = sweeplist(L, p, 1); - } while (p == old); - return p; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Finalization -** ======================================================= -*/ - -/* -** If possible, shrink string table -*/ -static void checkSizes (lua_State *L, global_State *g) { - if (g->gckind != KGC_EMERGENCY) { - l_mem olddebt = g->GCdebt; - if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ - luaS_resize(L, g->strt.size / 2); /* shrink it a little */ - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - } -} - - -static GCObject *udata2finalize (global_State *g) { - GCObject *o = g->tobefnz; /* get first element */ - lua_assert(tofinalize(o)); - g->tobefnz = o->next; /* remove it from 'tobefnz' list */ - o->next = g->allgc; /* return it to 'allgc' list */ - g->allgc = o; - resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ - if (issweepphase(g)) - makewhite(g, o); /* "sweep" object */ - return o; -} - - -static void dothecall (lua_State *L, void *ud) { - UNUSED(ud); - luaD_callnoyield(L, L->top - 2, 0); -} - - -static void GCTM (lua_State *L, int propagateerrors) { - global_State *g = G(L); - const TValue *tm; - TValue v; - setgcovalue(L, &v, udata2finalize(g)); - tm = luaT_gettmbyobj(L, &v, TM_GC); - if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ - int status; - lu_byte oldah = L->allowhook; - int running = g->gcrunning; - L->allowhook = 0; /* stop debug hooks during GC metamethod */ - g->gcrunning = 0; /* avoid GC steps */ - setobj2s(L, L->top, tm); /* push finalizer... */ - setobj2s(L, L->top + 1, &v); /* ... and its argument */ - L->top += 2; /* and (next line) call the finalizer */ - L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ - status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); - L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ - L->allowhook = oldah; /* restore hooks */ - g->gcrunning = running; /* restore state */ - if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ - if (status == LUA_ERRRUN) { /* is there an error object? */ - const char *msg = (ttisstring(L->top - 1)) - ? svalue(L->top - 1) - : "no message"; - luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); - status = LUA_ERRGCMM; /* error in __gc metamethod */ - } - luaD_throw(L, status); /* re-throw error */ - } - } -} - - -/* -** call a few (up to 'g->gcfinnum') finalizers -*/ -static int runafewfinalizers (lua_State *L) { - global_State *g = G(L); - unsigned int i; - lua_assert(!g->tobefnz || g->gcfinnum > 0); - for (i = 0; g->tobefnz && i < g->gcfinnum; i++) - GCTM(L, 1); /* call one finalizer */ - g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ - : g->gcfinnum * 2; /* else call a few more next time */ - return i; -} - - -/* -** call all pending finalizers -*/ -static void callallpendingfinalizers (lua_State *L) { - global_State *g = G(L); - while (g->tobefnz) - GCTM(L, 0); -} - - -/* -** find last 'next' field in list 'p' list (to add elements in its end) -*/ -static GCObject **findlast (GCObject **p) { - while (*p != NULL) - p = &(*p)->next; - return p; -} - - -/* -** move all unreachable objects (or 'all' objects) that need -** finalization from list 'finobj' to list 'tobefnz' (to be finalized) -*/ -static void separatetobefnz (global_State *g, int all) { - GCObject *curr; - GCObject **p = &g->finobj; - GCObject **lastnext = findlast(&g->tobefnz); - while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(tofinalize(curr)); - if (!(iswhite(curr) || all)) /* not being collected? */ - p = &curr->next; /* don't bother with it */ - else { - *p = curr->next; /* remove 'curr' from 'finobj' list */ - curr->next = *lastnext; /* link at the end of 'tobefnz' list */ - *lastnext = curr; - lastnext = &curr->next; - } - } -} - - -/* -** if object 'o' has a finalizer, remove it from 'allgc' list (must -** search the list to find it) and link it in 'finobj' list. -*/ -void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { - global_State *g = G(L); - if (tofinalize(o) || /* obj. is already marked... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ - return; /* nothing to be done */ - else { /* move 'o' to 'finobj' list */ - GCObject **p; - if (issweepphase(g)) { - makewhite(g, o); /* "sweep" object 'o' */ - if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ - g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ - } - /* search for pointer pointing to 'o' */ - for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } - *p = o->next; /* remove 'o' from 'allgc' list */ - o->next = g->finobj; /* link it in 'finobj' list */ - g->finobj = o; - l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ - } -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** GC control -** ======================================================= -*/ - - -/* -** Set a reasonable "time" to wait before starting a new GC cycle; cycle -** will start when memory use hits threshold. (Division by 'estimate' -** should be OK: it cannot be zero (because Lua cannot even start with -** less than PAUSEADJ bytes). -*/ -static void setpause (global_State *g) { - l_mem threshold, debt; - l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ - lua_assert(estimate > 0); - threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ - ? estimate * g->gcpause /* no overflow */ - : MAX_LMEM; /* overflow; truncate to maximum */ - debt = gettotalbytes(g) - threshold; - luaE_setdebt(g, debt); -} - - -/* -** Enter first sweep phase. -** The call to 'sweeplist' tries to make pointer point to an object -** inside the list (instead of to the header), so that the real sweep do -** not need to skip objects created between "now" and the start of the -** real sweep. -*/ -static void entersweep (lua_State *L) { - global_State *g = G(L); - g->gcstate = GCSswpallgc; - lua_assert(g->sweepgc == NULL); - g->sweepgc = sweeplist(L, &g->allgc, 1); -} - - -void luaC_freeallobjects (lua_State *L) { - global_State *g = G(L); - separatetobefnz(g, 1); /* separate all objects with finalizers */ - lua_assert(g->finobj == NULL); - callallpendingfinalizers(L); - lua_assert(g->tobefnz == NULL); - g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ - g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); - sweepwholelist(L, &g->allgc); - sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ - lua_assert(g->strt.nuse == 0); -} - - -static l_mem atomic (lua_State *L) { - global_State *g = G(L); - l_mem work; - GCObject *origweak, *origall; - GCObject *grayagain = g->grayagain; /* save original list */ - lua_assert(g->ephemeron == NULL && g->weak == NULL); - lua_assert(!iswhite(g->mainthread)); - g->gcstate = GCSinsideatomic; - g->GCmemtrav = 0; /* start counting work */ - markobject(g, L); /* mark running thread */ - /* registry and global metatables may be changed by API */ - markvalue(g, &g->l_registry); - markmt(g); /* mark global metatables */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - propagateall(g); /* propagate changes */ - work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ - g->gray = grayagain; - propagateall(g); /* traverse 'grayagain' list */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all strongly accessible objects are marked. */ - /* Clear values from weak tables, before checking finalizers */ - clearvalues(g, g->weak, NULL); - clearvalues(g, g->allweak, NULL); - origweak = g->weak; origall = g->allweak; - work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(g, 0); /* separate objects to be finalized */ - g->gcfinnum = 1; /* there may be objects to be finalized */ - markbeingfnz(g); /* mark objects that will be finalized */ - propagateall(g); /* remark, to propagate 'resurrection' */ - g->GCmemtrav = 0; /* restart counting */ - convergeephemerons(g); - /* at this point, all resurrected objects are marked. */ - /* remove dead objects from weak tables */ - clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ - /* clear values from resurrected weak tables */ - clearvalues(g, g->weak, origweak); - clearvalues(g, g->allweak, origall); - luaS_clearcache(g); - g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - work += g->GCmemtrav; /* complete counting */ - return work; /* estimate of memory marked by 'atomic' */ -} - - -static lu_mem sweepstep (lua_State *L, global_State *g, - int nextstate, GCObject **nextlist) { - if (g->sweepgc) { - l_mem olddebt = g->GCdebt; - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ - if (g->sweepgc) /* is there still something to sweep? */ - return (GCSWEEPMAX * GCSWEEPCOST); - } - /* else enter next state */ - g->gcstate = nextstate; - g->sweepgc = nextlist; - return 0; -} - - -static lu_mem singlestep (lua_State *L) { - global_State *g = G(L); - switch (g->gcstate) { - case GCSpause: { - g->GCmemtrav = g->strt.size * sizeof(GCObject*); - restartcollection(g); - g->gcstate = GCSpropagate; - return g->GCmemtrav; - } - case GCSpropagate: { - g->GCmemtrav = 0; - lua_assert(g->gray); - propagatemark(g); - if (g->gray == NULL) /* no more gray objects? */ - g->gcstate = GCSatomic; /* finish propagate phase */ - return g->GCmemtrav; /* memory traversed in this step */ - } - case GCSatomic: { - lu_mem work; - propagateall(g); /* make sure gray list is empty */ - work = atomic(L); /* work is what was traversed by 'atomic' */ - entersweep(L); - g->GCestimate = gettotalbytes(g); /* first estimate */; - return work; - } - case GCSswpallgc: { /* sweep "regular" objects */ - return sweepstep(L, g, GCSswpfinobj, &g->finobj); - } - case GCSswpfinobj: { /* sweep objects with finalizers */ - return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); - } - case GCSswptobefnz: { /* sweep objects to be finalized */ - return sweepstep(L, g, GCSswpend, NULL); - } - case GCSswpend: { /* finish sweeps */ - makewhite(g, g->mainthread); /* sweep main thread */ - checkSizes(L, g); - g->gcstate = GCScallfin; - return 0; - } - case GCScallfin: { /* call remaining finalizers */ - if (g->tobefnz && g->gckind != KGC_EMERGENCY) { - int n = runafewfinalizers(L); - return (n * GCFINALIZECOST); - } - else { /* emergency mode or no more finalizers */ - g->gcstate = GCSpause; /* finish collection */ - return 0; - } - } - default: lua_assert(0); return 0; - } -} - - -/* -** advances the garbage collector until it reaches a state allowed -** by 'statemask' -*/ -void luaC_runtilstate (lua_State *L, int statesmask) { - global_State *g = G(L); - while (!testbit(statesmask, g->gcstate)) - singlestep(L); -} - - -/* -** get GC debt and convert it from Kb to 'work units' (avoid zero debt -** and overflows) -*/ -static l_mem getdebt (global_State *g) { - l_mem debt = g->GCdebt; - int stepmul = g->gcstepmul; - if (debt <= 0) return 0; /* minimal debt */ - else { - debt = (debt / STEPMULADJ) + 1; - debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; - return debt; - } -} - -/* -** performs a basic GC step when collector is running -*/ -void luaC_step (lua_State *L) { - global_State *g = G(L); - l_mem debt = getdebt(g); /* GC deficit (be paid now) */ - if (!g->gcrunning) { /* not running? */ - luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ - return; - } - do { /* repeat until pause or enough "credit" (negative debt) */ - lu_mem work = singlestep(L); /* perform one single step */ - debt -= work; - } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); - if (g->gcstate == GCSpause) - setpause(g); /* pause until next cycle */ - else { - debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ - luaE_setdebt(g, debt); - runafewfinalizers(L); - } -} - - -/* -** Performs a full GC cycle; if 'isemergency', set a flag to avoid -** some operations which could change the interpreter state in some -** unexpected ways (running finalizers and shrinking some structures). -** Before running the collection, check 'keepinvariant'; if it is true, -** there may be some objects marked as black, so the collector has -** to sweep all objects to turn them back to white (as white has not -** changed, nothing will be collected). -*/ -void luaC_fullgc (lua_State *L, int isemergency) { - global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ - if (keepinvariant(g)) { /* black objects? */ - entersweep(L); /* sweep everything to turn them back to white */ - } - /* finish any pending sweep phase to start a new cycle */ - luaC_runtilstate(L, bitmask(GCSpause)); - luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ - luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ - /* estimate must be correct after a full GC cycle */ - lua_assert(g->GCestimate == gettotalbytes(g)); - luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ - g->gckind = KGC_NORMAL; - setpause(g); -} - -/* }====================================================== */ - - +/* +** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#define lgc_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +/* +** internal state for collector while inside the atomic phase. The +** collector should never be in this state while running regular code. +*/ +#define GCSinsideatomic (GCSpause + 1) + +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) + +/* maximum number of elements to sweep in each single step */ +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) + +/* cost of calling one finalizer */ +#define GCFINALIZECOST GCSWEEPCOST + + +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#define STEPMULADJ 200 + + +/* +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) +*/ +#define PAUSEADJ 100 + + +/* +** 'makewhite' erases all color bits then sets only the current white +** bit +*/ +#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) +#define makewhite(g,x) \ + (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) + +#define white2gray(x) resetbits(x->marked, WHITEBITS) +#define black2gray(x) resetbit(x->marked, BLACKBIT) + + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) + + +#define checkconsistency(obj) \ + lua_longassert(!iscollectable(obj) || righttt(obj)) + + +#define markvalue(g,o) { checkconsistency(o); \ + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } + +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } + +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + + +/* +** one after last element in a hash array +*/ +#define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) + + +/* +** link collectable object 'o' into list pointed by 'p' +*/ +#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) + + +/* +** If key is not marked, mark its entry as dead. This allows key to be +** collected, but keeps its entry in the table. A dead node is needed +** when Lua looks up for a key (it may be part of a chain) and when +** traversing a weak table (key might be removed from the table during +** traversal). Other places never manipulate dead keys, because its +** associated nil value is enough to signal that the entry is logically +** empty. +*/ +static void removeentry (Node *n) { + lua_assert(ttisnil(gval(n))); + if (valiswhite(gkey(n))) + setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ +} + + +/* +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak +** tables. Strings behave as 'values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (global_State *g, const TValue *o) { + if (!iscollectable(o)) return 0; + else if (ttisstring(o)) { + markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ + return 0; + } + else return iswhite(gcvalue(o)); +} + + +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. (If in sweep phase, clear the black +** object to white [sweep it] to avoid other barrier calls for this +** same object.) +*/ +void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + if (keepinvariant(g)) /* must keep invariant? */ + reallymarkobject(g, v); /* restore invariant */ + else { /* sweep phase */ + lua_assert(issweepphase(g)); + makewhite(g, o); /* mark main obj. as white to avoid other barriers */ + } +} + + +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ +void luaC_barrierback_ (lua_State *L, Table *t) { + global_State *g = G(L); + lua_assert(isblack(t) && !isdead(g, t)); + black2gray(t); /* make table gray (again) */ + linkgclist(t, g->grayagain); +} + + +/* +** barrier for assignments to closed upvalues. Because upvalues are +** shared among closures, it is impossible to know the color of all +** closures pointing to it. So, we assume that the object being assigned +** must be marked. +*/ +void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + if (keepinvariant(g)) + markobject(g, o); +} + + +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + white2gray(o); /* they will be gray forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; +} + + +/* +** create a new collectable object (with given type and size) and link +** it to 'allgc' list. +*/ +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { + global_State *g = G(L); + GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; + return o; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ + + +/* +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. Other objects are marked gray and added +** to appropriate list to be visited (and turned black) later. (Open +** upvalues are already linked in 'headuv' list.) +*/ +static void reallymarkobject (global_State *g, GCObject *o) { + reentry: + white2gray(o); + switch (o->tt) { + case LUA_TSHRSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); + break; + } + case LUA_TLNGSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); + break; + } + case LUA_TUSERDATA: { + TValue uvalue; + markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ + gray2black(o); + g->GCmemtrav += sizeudata(gco2u(o)); + getuservalue(g->mainthread, gco2u(o), &uvalue); + if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ + o = gcvalue(&uvalue); + goto reentry; + } + break; + } + case LUA_TLCL: { + linkgclist(gco2lcl(o), g->gray); + break; + } + case LUA_TCCL: { + linkgclist(gco2ccl(o), g->gray); + break; + } + case LUA_TTABLE: { + linkgclist(gco2t(o), g->gray); + break; + } + case LUA_TTHREAD: { + linkgclist(gco2th(o), g->gray); + break; + } + case LUA_TPROTO: { + linkgclist(gco2p(o), g->gray); + break; + } + default: lua_assert(0); break; + } +} + + +/* +** mark metamethods for basic types +*/ +static void markmt (global_State *g) { + int i; + for (i=0; i < LUA_NUMTAGS; i++) + markobjectN(g, g->mt[i]); +} + + +/* +** mark all objects in list of being-finalized +*/ +static void markbeingfnz (global_State *g) { + GCObject *o; + for (o = g->tobefnz; o != NULL; o = o->next) + markobject(g, o); +} + + +/* +** Mark all values stored in marked open upvalues from non-marked threads. +** (Values from marked threads were already marked when traversing the +** thread.) Remove from the list threads that no longer have upvalues and +** not-marked threads. +*/ +static void remarkupvals (global_State *g) { + lua_State *thread; + lua_State **p = &g->twups; + while ((thread = *p) != NULL) { + lua_assert(!isblack(thread)); /* threads are never black */ + if (isgray(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + if (uv->u.open.touched) { + markvalue(g, uv->v); /* remark upvalue's value */ + uv->u.open.touched = 0; + } + } + } + } +} + + +/* +** mark root set and reset all gray lists, to start a new collection +*/ +static void restartcollection (global_State *g) { + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ +static void traverseweakvalue (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ + int hasclears = (h->sizearray > 0); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ + } + } + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ +} + + +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). +*/ +static int traverseephemeron (global_State *g, Table *h) { + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has white keys */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ + Node *n, *limit = gnodelast(h); + unsigned int i; + /* traverse array part */ + for (i = 0; i < h->sizearray; i++) { + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); + } + } + /* traverse hash part */ + for (n = gnode(h, 0); n < limit; n++) { + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + hasww = 1; /* white-white entry */ + } + else if (valiswhite(gval(n))) { /* value not marked yet? */ + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ + } + } + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) /* traverse array part */ + markvalue(g, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ + } + } +} + + +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobjectN(g, h->metatable); + if (mode && ttisstring(mode) && /* is there a weak mode? */ + ((weakkey = strchr(svalue(mode), 'k')), + (weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + black2gray(h); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else /* all weak */ + linkgclist(h, g->allweak); /* nothing to traverse now */ + } + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * cast(size_t, allocsizenode(h)); +} + + +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ +static int traverseproto (global_State *g, Proto *f) { + int i; + if (f->cache && iswhite(f->cache)) + f->cache = NULL; /* allow cache to be collected */ + markobjectN(g, f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + markobjectN(g, f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ + markobjectN(g, f->p[i]); + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + markobjectN(g, f->locvars[i].varname); + return sizeof(Proto) + sizeof(Instruction) * f->sizecode + + sizeof(Proto *) * f->sizep + + sizeof(TValue) * f->sizek + + sizeof(int) * f->sizelineinfo + + sizeof(LocVar) * f->sizelocvars + + sizeof(Upvaldesc) * f->sizeupvalues; +} + + +static lu_mem traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return sizeCclosure(cl->nupvalues); +} + +/* +** open upvalues point to values in a thread, so those values should +** be marked when the thread is traversed except in the atomic phase +** (because then the value cannot be changed by the thread and the +** thread may not be traversed again) +*/ +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ + UpVal *uv = cl->upvals[i]; + if (uv != NULL) { + if (upisopen(uv) && g->gcstate != GCSinsideatomic) + uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ + else + markvalue(g, uv->v); + } + } + return sizeLclosure(cl->nupvalues); +} + + +static lu_mem traversethread (global_State *g, lua_State *th) { + StkId o = th->stack; + if (o == NULL) + return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSinsideatomic || + th->openupval == NULL || isintwups(th)); + for (; o < th->top; o++) /* mark live elements in the stack */ + markvalue(g, o); + if (g->gcstate == GCSinsideatomic) { /* final traversal? */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } + } + else if (g->gckind != KGC_EMERGENCY) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->nci); +} + + +/* +** traverse one gray object, turning it to black (except for threads, +** which are always gray). +*/ +static void propagatemark (global_State *g) { + lu_mem size; + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->tt) { + case LUA_TTABLE: { + Table *h = gco2t(o); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; + } + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseCclosure(g, cl); + break; + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; /* remove from 'gray' list */ + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ + black2gray(o); + size = traversethread(g, th); + break; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; + } + default: lua_assert(0); return; + } + g->GCmemtrav += size; +} + + +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); +} + + +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ + changed = 0; + while ((w = next) != NULL) { + next = gco2t(w)->gclist; + if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ + } + } + } while (changed); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Sweep Functions +** ======================================================= +*/ + + +/* +** clear entries with unmarked keys from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearkeys (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { + setnilvalue(gval(n)); /* remove value ... */ + } + if (ttisnil(gval(n))) /* is entry empty? */ + removeentry(n); /* remove entry from table */ + } + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearvalues (global_State *g, GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnodelast(h); + unsigned int i; + for (i = 0; i < h->sizearray; i++) { + TValue *o = &h->array[i]; + if (iscleared(g, o)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } +} + + +void luaC_upvdeccount (lua_State *L, UpVal *uv) { + lua_assert(uv->refcount > 0); + uv->refcount--; + if (uv->refcount == 0 && !upisopen(uv)) + luaM_free(L, uv); +} + + +static void freeLclosure (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = cl->upvals[i]; + if (uv) + luaC_upvdeccount(L, uv); + } + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); +} + + +static void freeobj (lua_State *L, GCObject *o) { + switch (o->tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TLCL: { + freeLclosure(L, gco2lcl(o)); + break; + } + case LUA_TCCL: { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + break; + } + case LUA_TTABLE: luaH_free(L, gco2t(o)); break; + case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; + case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; + case LUA_TSHRSTR: + luaS_remove(L, gco2ts(o)); /* remove it from hash table */ + luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + break; + case LUA_TLNGSTR: { + luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); + break; + } + default: lua_assert(0); + } +} + + +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); + + +/* +** sweep at most 'count' elements from a list of GCObjects erasing dead +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. +*/ +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { + global_State *g = G(L); + int ow = otherwhite(g); + int white = luaC_white(g); /* current white */ + while (*p != NULL && count-- > 0) { + GCObject *curr = *p; + int marked = curr->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & maskcolors) | white); + p = &curr->next; /* go to next element */ + } + } + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject **old = p; + do { + p = sweeplist(L, p, 1); + } while (p == old); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ + +/* +** If possible, shrink string table +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (g->gckind != KGC_EMERGENCY) { + l_mem olddebt = g->GCdebt; + if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ + luaS_resize(L, g->strt.size / 2); /* shrink it a little */ + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + } +} + + +static GCObject *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) + makewhite(g, o); /* "sweep" object */ + return o; +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_callnoyield(L, L->top - 2, 0); +} + + +static void GCTM (lua_State *L, int propagateerrors) { + global_State *g = G(L); + const TValue *tm; + TValue v; + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); + if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ + int status; + lu_byte oldah = L->allowhook; + int running = g->gcrunning; + L->allowhook = 0; /* stop debug hooks during GC metamethod */ + g->gcrunning = 0; /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + setobj2s(L, L->top + 1, &v); /* ... and its argument */ + L->top += 2; /* and (next line) call the finalizer */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ + L->allowhook = oldah; /* restore hooks */ + g->gcrunning = running; /* restore state */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-throw error */ + } + } +} + + +/* +** call a few (up to 'g->gcfinnum') finalizers +*/ +static int runafewfinalizers (lua_State *L) { + global_State *g = G(L); + unsigned int i; + lua_assert(!g->tobefnz || g->gcfinnum > 0); + for (i = 0; g->tobefnz && i < g->gcfinnum; i++) + GCTM(L, 1); /* call one finalizer */ + g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ + : g->gcfinnum * 2; /* else call a few more next time */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L, 0); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + +/* +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized) +*/ +static void separatetobefnz (global_State *g, int all) { + GCObject *curr; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); + while ((curr = *p) != NULL) { /* traverse all finalizable objects */ + lua_assert(tofinalize(curr)); + if (!(iswhite(curr) || all)) /* not being collected? */ + p = &curr->next; /* don't bother with it */ + else { + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->next; + } + } +} + + +/* +** if object 'o' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'finobj' list. +*/ +void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { + global_State *g = G(L); + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + return; /* nothing to be done */ + else { /* move 'o' to 'finobj' list */ + GCObject **p; + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ + } + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ + g->finobj = o; + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ + } +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** GC control +** ======================================================= +*/ + + +/* +** Set a reasonable "time" to wait before starting a new GC cycle; cycle +** will start when memory use hits threshold. (Division by 'estimate' +** should be OK: it cannot be zero (because Lua cannot even start with +** less than PAUSEADJ bytes). +*/ +static void setpause (global_State *g) { + l_mem threshold, debt; + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); + threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * g->gcpause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = gettotalbytes(g) - threshold; + luaE_setdebt(g, debt); +} + + +/* +** Enter first sweep phase. +** The call to 'sweeplist' tries to make pointer point to an object +** inside the list (instead of to the header), so that the real sweep do +** not need to skip objects created between "now" and the start of the +** real sweep. +*/ +static void entersweep (lua_State *L) { + global_State *g = G(L); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeplist(L, &g->allgc, 1); +} + + +void luaC_freeallobjects (lua_State *L) { + global_State *g = G(L); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); + callallpendingfinalizers(L); + lua_assert(g->tobefnz == NULL); + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->finobj); + sweepwholelist(L, &g->allgc); + sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ + lua_assert(g->strt.nuse == 0); +} + + +static l_mem atomic (lua_State *L) { + global_State *g = G(L); + l_mem work; + GCObject *origweak, *origall; + GCObject *grayagain = g->grayagain; /* save original list */ + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSinsideatomic; + g->GCmemtrav = 0; /* start counting work */ + markobject(g, L); /* mark running thread */ + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark global metatables */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + propagateall(g); /* propagate changes */ + work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ + g->gray = grayagain; + propagateall(g); /* traverse 'grayagain' list */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ + /* Clear values from weak tables, before checking finalizers */ + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ + separatetobefnz(g, 0); /* separate objects to be finalized */ + g->gcfinnum = 1; /* there may be objects to be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate 'resurrection' */ + g->GCmemtrav = 0; /* restart counting */ + convergeephemerons(g); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ + /* clear values from resurrected weak tables */ + clearvalues(g, g->weak, origweak); + clearvalues(g, g->allweak, origall); + luaS_clearcache(g); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ +} + + +static lu_mem sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + if (g->sweepgc) /* is there still something to sweep? */ + return (GCSWEEPMAX * GCSWEEPCOST); + } + /* else enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; +} + + +static lu_mem singlestep (lua_State *L) { + global_State *g = G(L); + switch (g->gcstate) { + case GCSpause: { + g->GCmemtrav = g->strt.size * sizeof(GCObject*); + restartcollection(g); + g->gcstate = GCSpropagate; + return g->GCmemtrav; + } + case GCSpropagate: { + g->GCmemtrav = 0; + lua_assert(g->gray); + propagatemark(g); + if (g->gray == NULL) /* no more gray objects? */ + g->gcstate = GCSatomic; /* finish propagate phase */ + return g->GCmemtrav; /* memory traversed in this step */ + } + case GCSatomic: { + lu_mem work; + propagateall(g); /* make sure gray list is empty */ + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + return work; + } + case GCSswpallgc: { /* sweep "regular" objects */ + return sweepstep(L, g, GCSswpfinobj, &g->finobj); + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + } + case GCSswptobefnz: { /* sweep objects to be finalized */ + return sweepstep(L, g, GCSswpend, NULL); + } + case GCSswpend: { /* finish sweeps */ + makewhite(g, g->mainthread); /* sweep main thread */ + checkSizes(L, g); + g->gcstate = GCScallfin; + return 0; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && g->gckind != KGC_EMERGENCY) { + int n = runafewfinalizers(L); + return (n * GCFINALIZECOST); + } + else { /* emergency mode or no more finalizers */ + g->gcstate = GCSpause; /* finish collection */ + return 0; + } + } + default: lua_assert(0); return 0; + } +} + + +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { + global_State *g = G(L); + while (!testbit(statesmask, g->gcstate)) + singlestep(L); +} + + +/* +** get GC debt and convert it from Kb to 'work units' (avoid zero debt +** and overflows) +*/ +static l_mem getdebt (global_State *g) { + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (debt <= 0) return 0; /* minimal debt */ + else { + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; + return debt; + } +} + +/* +** performs a basic GC step when collector is running +*/ +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem debt = getdebt(g); /* GC deficit (be paid now) */ + if (!g->gcrunning) { /* not running? */ + luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ + return; + } + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g); /* pause until next cycle */ + else { + debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); + runafewfinalizers(L); + } +} + + +/* +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). +*/ +void luaC_fullgc (lua_State *L, int isemergency) { + global_State *g = G(L); + lua_assert(g->gckind == KGC_NORMAL); + if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ + if (keepinvariant(g)) { /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ + } + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + g->gckind = KGC_NORMAL; + setpause(g); +} + +/* }====================================================== */ + + diff --git a/libs/lua/source/linit.c b/libs/lua/source/linit.c index 671069a1..f9bf47e7 100644 --- a/libs/lua/source/linit.c +++ b/libs/lua/source/linit.c @@ -1,67 +1,67 @@ -/* -** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ -** Initialization of libraries for lua.c and other clients -** See Copyright Notice in lua.h -*/ - - -#define linit_c -#define LUA_LIB - -/* -** If you embed Lua in your program and need to open the standard -** libraries, call luaL_openlibs in your program. If you need a -** different set of libraries, copy this file to your project and edit -** it to suit your needs. -** -** You can also *preload* libraries, so that a later 'require' can -** open the library, which is already linked to the application. -** For that, do the following code: -** -** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); -** lua_pushcfunction(L, luaopen_modname); -** lua_setfield(L, -2, modname); -** lua_pop(L, 1); // remove PRELOAD table -*/ - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lualib.h" -#include "lauxlib.h" - - -/* -** these libs are loaded by lua.c and are readily available to any Lua -** program -*/ -static const luaL_Reg loadedlibs[] = { - {"_G", luaopen_base}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_COLIBNAME, luaopen_coroutine}, - {LUA_TABLIBNAME, luaopen_table}, - //{LUA_IOLIBNAME, luaopen_io}, - //{LUA_OSLIBNAME, luaopen_os}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_UTF8LIBNAME, luaopen_utf8}, - {LUA_DBLIBNAME, luaopen_debug}, -#if defined(LUA_COMPAT_BITLIB) - {LUA_BITLIBNAME, luaopen_bit32}, -#endif - {NULL, NULL} -}; - - -LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib; - /* "require" functions from 'loadedlibs' and set results to global table */ - for (lib = loadedlibs; lib->func; lib++) { - luaL_requiref(L, lib->name, lib->func, 1); - lua_pop(L, 1); /* remove lib */ - } -} +/* +** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ +** Initialization of libraries for lua.c and other clients +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove PRELOAD table +*/ + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {"_G", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + //{LUA_IOLIBNAME, luaopen_io}, + //{LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, + {LUA_DBLIBNAME, luaopen_debug}, +#if defined(LUA_COMPAT_BITLIB) + {LUA_BITLIBNAME, luaopen_bit32}, +#endif + {NULL, NULL} +}; + + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } +} diff --git a/libs/lua/source/liolib.c b/libs/lua/source/liolib.c index 8a9e75cd..f537a02d 100644 --- a/libs/lua/source/liolib.c +++ b/libs/lua/source/liolib.c @@ -1,776 +1,776 @@ -/* -** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - -#define liolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - - -/* -** Change this macro to accept other modes for 'fopen' besides -** the standard ones. -*/ -#if !defined(l_checkmode) - -/* accepted extensions to 'mode' in 'fopen' */ -#if !defined(L_MODEEXT) -#define L_MODEEXT "b" -#endif - -/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ -static int l_checkmode (const char *mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && - (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ - (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ -} - -#endif - -/* -** {====================================================== -** l_popen spawns a new process connected to the current -** one through the file streams. -** ======================================================= -*/ - -#if !defined(l_popen) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) -#define l_pclose(L,file) (pclose(file)) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#define l_popen(L,c,m) (_popen(c,m)) -#define l_pclose(L,file) (_pclose(file)) - -#else /* }{ */ - -/* ISO C definitions */ -#define l_popen(L,c,m) \ - ((void)((void)c, m), \ - luaL_error(L, "'popen' not supported"), \ - (FILE*)0) -#define l_pclose(L,file) ((void)L, (void)file, -1) - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - -#if !defined(l_getc) /* { */ - -#if defined(LUA_USE_POSIX) -#define l_getc(f) getc_unlocked(f) -#define l_lockfile(f) flockfile(f) -#define l_unlockfile(f) funlockfile(f) -#else -#define l_getc(f) getc(f) -#define l_lockfile(f) ((void)0) -#define l_unlockfile(f) ((void)0) -#endif - -#endif /* } */ - - -/* -** {====================================================== -** l_fseek: configuration for longer offsets -** ======================================================= -*/ - -#if !defined(l_fseek) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define l_fseek(f,o,w) fseeko(f,o,w) -#define l_ftell(f) ftello(f) -#define l_seeknum off_t - -#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ - && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ - -/* Windows (but not DDK) and Visual C++ 2005 or higher */ -#define l_fseek(f,o,w) _fseeki64(f,o,w) -#define l_ftell(f) _ftelli64(f) -#define l_seeknum __int64 - -#else /* }{ */ - -/* ISO C definitions */ -#define l_fseek(f,o,w) fseek(f,o,w) -#define l_ftell(f) ftell(f) -#define l_seeknum long - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - -#define IO_PREFIX "_IO_" -#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) -#define IO_INPUT (IO_PREFIX "input") -#define IO_OUTPUT (IO_PREFIX "output") - - -typedef luaL_Stream LStream; - - -#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) - -#define isclosed(p) ((p)->closef == NULL) - - -static int io_type (lua_State *L) { - LStream *p; - luaL_checkany(L, 1); - p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); - if (p == NULL) - lua_pushnil(L); /* not a file */ - else if (isclosed(p)) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", p->f); - return 1; -} - - -static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - luaL_error(L, "attempt to use a closed file"); - lua_assert(p->f); - return p->f; -} - - -/* -** When creating file handles, always creates a 'closed' file handle -** before opening the actual file; so, if there is a memory error, the -** handle is in a consistent state. -*/ -static LStream *newprefile (lua_State *L) { - LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); - p->closef = NULL; /* mark file handle as 'closed' */ - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - - -/* -** Calls the 'close' function from a file handle. The 'volatile' avoids -** a bug in some versions of the Clang compiler (e.g., clang 3.0 for -** 32 bits). -*/ -static int aux_close (lua_State *L) { - LStream *p = tolstream(L); - volatile lua_CFunction cf = p->closef; - p->closef = NULL; /* mark stream as closed */ - return (*cf)(L); /* close it */ -} - - -static int f_close (lua_State *L) { - tofile(L); /* make sure argument is an open stream */ - return aux_close(L); -} - - -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ - return f_close(L); -} - - -static int f_gc (lua_State *L) { - LStream *p = tolstream(L); - if (!isclosed(p) && p->f != NULL) - aux_close(L); /* ignore closed and incompletely open files */ - return 0; -} - - -/* -** function to close regular files -*/ -static int io_fclose (lua_State *L) { - LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); -} - - -static LStream *newfile (lua_State *L) { - LStream *p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; -} - - -static void opencheck (lua_State *L, const char *fname, const char *mode) { - LStream *p = newfile(L); - p->f = fopen(fname, mode); - if (p->f == NULL) - luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); -} - - -static int io_open (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newfile(L); - const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - p->f = fopen(filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -/* -** function to close 'popen' files -*/ -static int io_pclose (lua_State *L) { - LStream *p = tolstream(L); - return luaL_execresult(L, l_pclose(L, p->f)); -} - - -static int io_popen (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newprefile(L); - p->f = l_popen(L, filename, mode); - p->closef = &io_pclose; - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -static int io_tmpfile (lua_State *L) { - LStream *p = newfile(L); - p->f = tmpfile(); - return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; -} - - -static FILE *getiofile (lua_State *L, const char *findex) { - LStream *p; - lua_getfield(L, LUA_REGISTRYINDEX, findex); - p = (LStream *)lua_touserdata(L, -1); - if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); - return p->f; -} - - -static int g_iofile (lua_State *L, const char *f, const char *mode) { - if (!lua_isnoneornil(L, 1)) { - const char *filename = lua_tostring(L, 1); - if (filename) - opencheck(L, filename, mode); - else { - tofile(L); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_setfield(L, LUA_REGISTRYINDEX, f); - } - /* return current value */ - lua_getfield(L, LUA_REGISTRYINDEX, f); - return 1; -} - - -static int io_input (lua_State *L) { - return g_iofile(L, IO_INPUT, "r"); -} - - -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); -} - - -static int io_readline (lua_State *L); - - -/* -** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit -** in the limit for upvalues of a closure) -*/ -#define MAXARGLINE 250 - -static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ - luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ - lua_pushcclosure(L, io_readline, 3 + n); -} - - -static int f_lines (lua_State *L) { - tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 0); - return 1; -} - - -static int io_lines (lua_State *L) { - int toclose; - if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ - if (lua_isnil(L, 1)) { /* no file name? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ - lua_replace(L, 1); /* put it at index 1 */ - tofile(L); /* check that it's a valid file handle */ - toclose = 0; /* do not close it after iteration */ - } - else { /* open a new file */ - const char *filename = luaL_checkstring(L, 1); - opencheck(L, filename, "r"); - lua_replace(L, 1); /* put file at index 1 */ - toclose = 1; /* close it after iteration */ - } - aux_lines(L, toclose); - return 1; -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -/* maximum length of a numeral */ -#if !defined (L_MAXLENNUM) -#define L_MAXLENNUM 200 -#endif - - -/* auxiliary structure used by 'read_number' */ -typedef struct { - FILE *f; /* file being read */ - int c; /* current character (look ahead) */ - int n; /* number of elements in buffer 'buff' */ - char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ -} RN; - - -/* -** Add current char to buffer (if not out of space) and read next one -*/ -static int nextc (RN *rn) { - if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ - rn->buff[0] = '\0'; /* invalidate result */ - return 0; /* fail */ - } - else { - rn->buff[rn->n++] = rn->c; /* save current char */ - rn->c = l_getc(rn->f); /* read next one */ - return 1; - } -} - - -/* -** Accept current char if it is in 'set' (of size 2) -*/ -static int test2 (RN *rn, const char *set) { - if (rn->c == set[0] || rn->c == set[1]) - return nextc(rn); - else return 0; -} - - -/* -** Read a sequence of (hex)digits -*/ -static int readdigits (RN *rn, int hex) { - int count = 0; - while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) - count++; - return count; -} - - -/* -** Read a number: first reads a valid prefix of a numeral into a buffer. -** Then it calls 'lua_stringtonumber' to check whether the format is -** correct and to convert it to a Lua number -*/ -static int read_number (lua_State *L, FILE *f) { - RN rn; - int count = 0; - int hex = 0; - char decp[2]; - rn.f = f; rn.n = 0; - decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ - decp[1] = '.'; /* always accept a dot */ - l_lockfile(rn.f); - do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ - test2(&rn, "-+"); /* optional signal */ - if (test2(&rn, "00")) { - if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ - else count = 1; /* count initial '0' as a valid digit */ - } - count += readdigits(&rn, hex); /* integral part */ - if (test2(&rn, decp)) /* decimal point? */ - count += readdigits(&rn, hex); /* fractional part */ - if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ - test2(&rn, "-+"); /* exponent signal */ - readdigits(&rn, 0); /* exponent digits */ - } - ungetc(rn.c, rn.f); /* unread look-ahead char */ - l_unlockfile(rn.f); - rn.buff[rn.n] = '\0'; /* finish string */ - if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ - return 1; /* ok */ - else { /* invalid format */ - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ - } -} - - -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); /* no-op when c == EOF */ - lua_pushliteral(L, ""); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f, int chop) { - luaL_Buffer b; - int c = '\0'; - luaL_buffinit(L, &b); - while (c != EOF && c != '\n') { /* repeat until end of line */ - char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ - int i = 0; - l_lockfile(f); /* no memory errors can happen inside the lock */ - while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') - buff[i++] = c; - l_unlockfile(f); - luaL_addsize(&b, i); - } - if (!chop && c == '\n') /* want a newline and have one? */ - luaL_addchar(&b, c); /* add ending newline to result */ - luaL_pushresult(&b); /* close buffer */ - /* return ok if read something (either a newline or something else) */ - return (c == '\n' || lua_rawlen(L, -1) > 0); -} - - -static void read_all (lua_State *L, FILE *f) { - size_t nr; - luaL_Buffer b; - luaL_buffinit(L, &b); - do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ - char *p = luaL_prepbuffer(&b); - nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); - luaL_addsize(&b, nr); - } while (nr == LUAL_BUFFERSIZE); - luaL_pushresult(&b); /* close buffer */ -} - - -static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t nr; /* number of chars actually read */ - char *p; - luaL_Buffer b; - luaL_buffinit(L, &b); - p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ - nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ - luaL_addsize(&b, nr); - luaL_pushresult(&b); /* close buffer */ - return (nr > 0); /* true iff read something */ -} - - -static int g_read (lua_State *L, FILE *f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - clearerr(f); - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f, 1); - n = first+1; /* to return 1 result */ - } - else { /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - success = 1; - for (n = first; nargs-- && success; n++) { - if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)luaL_checkinteger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = luaL_checkstring(L, n); - if (*p == '*') p++; /* skip optional '*' (for compatibility) */ - switch (*p) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f, 1); - break; - case 'L': /* line with end-of-line */ - success = read_line(L, f, 0); - break; - case 'a': /* file */ - read_all(L, f); /* read entire file */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (ferror(f)) - return luaL_fileresult(L, 0, NULL); - if (!success) { - lua_pop(L, 1); /* remove last result */ - lua_pushnil(L); /* push nil instead */ - } - return n - first; -} - - -static int io_read (lua_State *L) { - return g_read(L, getiofile(L, IO_INPUT), 1); -} - - -static int f_read (lua_State *L) { - return g_read(L, tofile(L), 2); -} - - -static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); - int i; - int n = (int)lua_tointeger(L, lua_upvalueindex(2)); - if (isclosed(p)) /* file is already closed? */ - return luaL_error(L, "file is already closed"); - lua_settop(L , 1); - luaL_checkstack(L, n, "too many arguments"); - for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ - lua_pushvalue(L, lua_upvalueindex(3 + i)); - n = g_read(L, p->f, 2); /* 'n' is number of results */ - lua_assert(n > 0); /* should return at least a nil */ - if (lua_toboolean(L, -n)) /* read at least one value? */ - return n; /* return them */ - else { /* first result is nil: EOF or error */ - if (n > 1) { /* is there error information? */ - /* 2nd result is error message */ - return luaL_error(L, "%s", lua_tostring(L, -n + 1)); - } - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(1)); - aux_close(L); /* close it */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - arg; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - int len = lua_isinteger(L, arg) - ? fprintf(f, LUA_INTEGER_FMT, - (LUAI_UACINT)lua_tointeger(L, arg)) - : fprintf(f, LUA_NUMBER_FMT, - (LUAI_UACNUMBER)lua_tonumber(L, arg)); - status = status && (len > 0); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - if (status) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); -} - - -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); -} - - -static int f_write (lua_State *L) { - FILE *f = tofile(L); - lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ - return g_write(L, f, 2); -} - - -static int f_seek (lua_State *L) { - static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; - static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer p3 = luaL_optinteger(L, 3, 0); - l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Integer)offset == p3, 3, - "not an integer in proper range"); - op = l_fseek(f, offset, mode[op]); - if (op) - return luaL_fileresult(L, 0, NULL); /* error */ - else { - lua_pushinteger(L, (lua_Integer)l_ftell(f)); - return 1; - } -} - - -static int f_setvbuf (lua_State *L) { - static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; - static const char *const modenames[] = {"no", "full", "line", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); - return luaL_fileresult(L, res == 0, NULL); -} - - - -static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); -} - - -static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); -} - - -/* -** functions for 'io' library -*/ -static const luaL_Reg iolib[] = { - {"close", io_close}, - {"flush", io_flush}, - {"input", io_input}, - {"lines", io_lines}, - {"open", io_open}, - {"output", io_output}, - {"popen", io_popen}, - {"read", io_read}, - {"tmpfile", io_tmpfile}, - {"type", io_type}, - {"write", io_write}, - {NULL, NULL} -}; - - -/* -** methods for file handles -*/ -static const luaL_Reg flib[] = { - {"close", f_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, - {"seek", f_seek}, - {"setvbuf", f_setvbuf}, - {"write", f_write}, - {"__gc", f_gc}, - {"__tostring", f_tostring}, - {NULL, NULL} -}; - - -static void createmeta (lua_State *L) { - luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ - lua_pop(L, 1); /* pop new metatable */ -} - - -/* -** function to (not) close the standard files stdin, stdout, and stderr -*/ -static int io_noclose (lua_State *L) { - LStream *p = tolstream(L); - p->closef = &io_noclose; /* keep file opened */ - lua_pushnil(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; -} - - -static void createstdfile (lua_State *L, FILE *f, const char *k, - const char *fname) { - LStream *p = newprefile(L); - p->f = f; - p->closef = &io_noclose; - if (k != NULL) { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ - } - lua_setfield(L, -2, fname); /* add file to module */ -} - - -LUAMOD_API int luaopen_io (lua_State *L) { - luaL_newlib(L, iolib); /* new module */ - createmeta(L); - /* create (and set) default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, NULL, "stderr"); - return 1; -} - +/* +** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +#define liolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +static int l_checkmode (const char *mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +} + +#endif + +/* +** {====================================================== +** l_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(l_popen) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)((void)c, m), \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + +/* +** {====================================================== +** l_fseek: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(l_fseek) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ + +/* Windows (but not DDK) and Visual C++ 2005 or higher */ +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else /* }{ */ + +/* ISO C definitions */ +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) +#define IO_INPUT (IO_PREFIX "input") +#define IO_OUTPUT (IO_PREFIX "output") + + +typedef luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + lua_pushnil(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** When creating file handles, always creates a 'closed' file handle +** before opening the actual file; so, if there is a memory error, the +** handle is in a consistent state. +*/ +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int f_close (lua_State *L) { + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + return f_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (p->f == NULL) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newfile(L); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + return luaL_execresult(L, l_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); + return p->f; +} + + +static int g_iofile (lua_State *L, const char *f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + +static void aux_lines (lua_State *L, int toclose) { + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + int c = '\0'; + luaL_buffinit(L, &b); + while (c != EOF && c != '\n') { /* repeat until end of line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); + } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); +} + + +static void read_all (lua_State *L, FILE *f) { + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f, 1); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is nil: EOF or error */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (status) return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (op) + return luaL_fileresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg flib[] = { + {"close", f_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/libs/lua/source/llex.c b/libs/lua/source/llex.c index 66fd411b..f4ea5c2f 100644 --- a/libs/lua/source/llex.c +++ b/libs/lua/source/llex.c @@ -1,565 +1,565 @@ -/* -** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - -#define llex_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lctype.h" -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "llex.h" -#include "lobject.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lzio.h" - - - -#define next(ls) (ls->current = zgetc(ls->z)) - - - -#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') - - -/* ORDER RESERVED */ -static const char *const luaX_tokens [] = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "//", "..", "...", "==", ">=", "<=", "~=", - "<<", ">>", "::", "", - "", "", "", "" -}; - - -#define save_and_next(ls) (save(ls, ls->current), next(ls)) - - -static l_noret lexerror (LexState *ls, const char *msg, int token); - - -static void save (LexState *ls, int c) { - Mbuffer *b = ls->buff; - if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { - size_t newsize; - if (luaZ_sizebuffer(b) >= MAX_SIZE/2) - lexerror(ls, "lexical element too long", 0); - newsize = luaZ_sizebuffer(b) * 2; - luaZ_resizebuffer(ls->L, b, newsize); - } - b->buffer[luaZ_bufflen(b)++] = cast(char, c); -} - - -void luaX_init (lua_State *L) { - int i; - TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ - luaC_fix(L, obj2gco(e)); /* never collect this name */ - for (i=0; iextra = cast_byte(i+1); /* reserved word */ - } -} - - -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { /* single-byte symbols? */ - lua_assert(token == cast_uchar(token)); - return luaO_pushfstring(ls->L, "'%c'", token); - } - else { - const char *s = luaX_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ - return luaO_pushfstring(ls->L, "'%s'", s); - else /* names, strings, and numerals */ - return s; - } -} - - -static const char *txtToken (LexState *ls, int token) { - switch (token) { - case TK_NAME: case TK_STRING: - case TK_FLT: case TK_INT: - save(ls, '\0'); - return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); - default: - return luaX_token2str(ls, token); - } -} - - -static l_noret lexerror (LexState *ls, const char *msg, int token) { - msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); - if (token) - luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); - luaD_throw(ls->L, LUA_ERRSYNTAX); -} - - -l_noret luaX_syntaxerror (LexState *ls, const char *msg) { - lexerror(ls, msg, ls->t.token); -} - - -/* -** creates a new string and anchors it in scanner's table so that -** it will not be collected until the end of the compilation -** (by that time it should be anchored somewhere) -*/ -TString *luaX_newstring (LexState *ls, const char *str, size_t l) { - lua_State *L = ls->L; - TValue *o; /* entry for 'str' */ - TString *ts = luaS_newlstr(L, str, l); /* create new string */ - setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? */ - /* boolean value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setbvalue(o, 1); /* t[string] = true */ - luaC_checkGC(L); - } - else { /* string already present */ - ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ - } - L->top--; /* remove string from stack */ - return ts; -} - - -/* -** increment line number and skips newline sequence (any of -** \n, \r, \n\r, or \r\n) -*/ -static void inclinenumber (LexState *ls) { - int old = ls->current; - lua_assert(currIsNewline(ls)); - next(ls); /* skip '\n' or '\r' */ - if (currIsNewline(ls) && ls->current != old) - next(ls); /* skip '\n\r' or '\r\n' */ - if (++ls->linenumber >= MAX_INT) - lexerror(ls, "chunk has too many lines", 0); -} - - -void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, - int firstchar) { - ls->t.token = 0; - ls->L = L; - ls->current = firstchar; - ls->lookahead.token = TK_EOS; /* no look-ahead token */ - ls->z = z; - ls->fs = NULL; - ls->linenumber = 1; - ls->lastline = 1; - ls->source = source; - ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ - luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ -} - - - -/* -** ======================================================= -** LEXICAL ANALYZER -** ======================================================= -*/ - - -static int check_next1 (LexState *ls, int c) { - if (ls->current == c) { - next(ls); - return 1; - } - else return 0; -} - - -/* -** Check whether current char is in set 'set' (with two chars) and -** saves it -*/ -static int check_next2 (LexState *ls, const char *set) { - lua_assert(set[2] == '\0'); - if (ls->current == set[0] || ls->current == set[1]) { - save_and_next(ls); - return 1; - } - else return 0; -} - - -/* LUA_NUMBER */ -/* -** this function is quite liberal in what it accepts, as 'luaO_str2num' -** will reject ill-formed numerals. -*/ -static int read_numeral (LexState *ls, SemInfo *seminfo) { - TValue obj; - const char *expo = "Ee"; - int first = ls->current; - lua_assert(lisdigit(ls->current)); - save_and_next(ls); - if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ - expo = "Pp"; - for (;;) { - if (check_next2(ls, expo)) /* exponent part? */ - check_next2(ls, "-+"); /* optional exponent sign */ - if (lisxdigit(ls->current)) - save_and_next(ls); - else if (ls->current == '.') - save_and_next(ls); - else break; - } - save(ls, '\0'); - if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ - lexerror(ls, "malformed number", TK_FLT); - if (ttisinteger(&obj)) { - seminfo->i = ivalue(&obj); - return TK_INT; - } - else { - lua_assert(ttisfloat(&obj)); - seminfo->r = fltvalue(&obj); - return TK_FLT; - } -} - - -/* -** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return -** its number of '='s; otherwise, return a negative number (-1 iff there -** are no '='s after initial bracket) -*/ -static int skip_sep (LexState *ls) { - int count = 0; - int s = ls->current; - lua_assert(s == '[' || s == ']'); - save_and_next(ls); - while (ls->current == '=') { - save_and_next(ls); - count++; - } - return (ls->current == s) ? count : (-count) - 1; -} - - -static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - int line = ls->linenumber; /* initial line (for error message) */ - save_and_next(ls); /* skip 2nd '[' */ - if (currIsNewline(ls)) /* string starts with a newline? */ - inclinenumber(ls); /* skip it */ - for (;;) { - switch (ls->current) { - case EOZ: { /* error */ - const char *what = (seminfo ? "string" : "comment"); - const char *msg = luaO_pushfstring(ls->L, - "unfinished long %s (starting at line %d)", what, line); - lexerror(ls, msg, TK_EOS); - break; /* to avoid warnings */ - } - case ']': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd ']' */ - goto endloop; - } - break; - } - case '\n': case '\r': { - save(ls, '\n'); - inclinenumber(ls); - if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ - break; - } - default: { - if (seminfo) save_and_next(ls); - else next(ls); - } - } - } endloop: - if (seminfo) - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), - luaZ_bufflen(ls->buff) - 2*(2 + sep)); -} - - -static void esccheck (LexState *ls, int c, const char *msg) { - if (!c) { - if (ls->current != EOZ) - save_and_next(ls); /* add current to buffer for error message */ - lexerror(ls, msg, TK_STRING); - } -} - - -static int gethexa (LexState *ls) { - save_and_next(ls); - esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); - return luaO_hexavalue(ls->current); -} - - -static int readhexaesc (LexState *ls) { - int r = gethexa(ls); - r = (r << 4) + gethexa(ls); - luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ - return r; -} - - -static unsigned long readutf8esc (LexState *ls) { - unsigned long r; - int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ - save_and_next(ls); /* skip 'u' */ - esccheck(ls, ls->current == '{', "missing '{'"); - r = gethexa(ls); /* must have at least one digit */ - while ((save_and_next(ls), lisxdigit(ls->current))) { - i++; - r = (r << 4) + luaO_hexavalue(ls->current); - esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); - } - esccheck(ls, ls->current == '}', "missing '}'"); - next(ls); /* skip '}' */ - luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ - return r; -} - - -static void utf8esc (LexState *ls) { - char buff[UTF8BUFFSZ]; - int n = luaO_utf8esc(buff, readutf8esc(ls)); - for (; n > 0; n--) /* add 'buff' to string */ - save(ls, buff[UTF8BUFFSZ - n]); -} - - -static int readdecesc (LexState *ls) { - int i; - int r = 0; /* result accumulator */ - for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ - r = 10*r + ls->current - '0'; - save_and_next(ls); - } - esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); - luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ - return r; -} - - -static void read_string (LexState *ls, int del, SemInfo *seminfo) { - save_and_next(ls); /* keep delimiter (for error messages) */ - while (ls->current != del) { - switch (ls->current) { - case EOZ: - lexerror(ls, "unfinished string", TK_EOS); - break; /* to avoid warnings */ - case '\n': - case '\r': - lexerror(ls, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': { /* escape sequences */ - int c; /* final character to be saved */ - save_and_next(ls); /* keep '\\' for error messages */ - switch (ls->current) { - case 'a': c = '\a'; goto read_save; - case 'b': c = '\b'; goto read_save; - case 'f': c = '\f'; goto read_save; - case 'n': c = '\n'; goto read_save; - case 'r': c = '\r'; goto read_save; - case 't': c = '\t'; goto read_save; - case 'v': c = '\v'; goto read_save; - case 'x': c = readhexaesc(ls); goto read_save; - case 'u': utf8esc(ls); goto no_save; - case '\n': case '\r': - inclinenumber(ls); c = '\n'; goto only_save; - case '\\': case '\"': case '\'': - c = ls->current; goto read_save; - case EOZ: goto no_save; /* will raise an error next loop */ - case 'z': { /* zap following span of spaces */ - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - next(ls); /* skip the 'z' */ - while (lisspace(ls->current)) { - if (currIsNewline(ls)) inclinenumber(ls); - else next(ls); - } - goto no_save; - } - default: { - esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); - c = readdecesc(ls); /* digital escape '\ddd' */ - goto only_save; - } - } - read_save: - next(ls); - /* go through */ - only_save: - luaZ_buffremove(ls->buff, 1); /* remove '\\' */ - save(ls, c); - /* go through */ - no_save: break; - } - default: - save_and_next(ls); - } - } - save_and_next(ls); /* skip delimiter */ - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, - luaZ_bufflen(ls->buff) - 2); -} - - -static int llex (LexState *ls, SemInfo *seminfo) { - luaZ_resetbuffer(ls->buff); - for (;;) { - switch (ls->current) { - case '\n': case '\r': { /* line breaks */ - inclinenumber(ls); - break; - } - case ' ': case '\f': case '\t': case '\v': { /* spaces */ - next(ls); - break; - } - case '-': { /* '-' or '--' (comment) */ - next(ls); - if (ls->current != '-') return '-'; - /* else is a comment */ - next(ls); - if (ls->current == '[') { /* long comment? */ - int sep = skip_sep(ls); - luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ - if (sep >= 0) { - read_long_string(ls, NULL, sep); /* skip long comment */ - luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ - break; - } - } - /* else short comment */ - while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); /* skip until end of line (or end of file) */ - break; - } - case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); - if (sep >= 0) { - read_long_string(ls, seminfo, sep); - return TK_STRING; - } - else if (sep != -1) /* '[=...' missing second bracket */ - lexerror(ls, "invalid long string delimiter", TK_STRING); - return '['; - } - case '=': { - next(ls); - if (check_next1(ls, '=')) return TK_EQ; - else return '='; - } - case '<': { - next(ls); - if (check_next1(ls, '=')) return TK_LE; - else if (check_next1(ls, '<')) return TK_SHL; - else return '<'; - } - case '>': { - next(ls); - if (check_next1(ls, '=')) return TK_GE; - else if (check_next1(ls, '>')) return TK_SHR; - else return '>'; - } - case '/': { - next(ls); - if (check_next1(ls, '/')) return TK_IDIV; - else return '/'; - } - case '~': { - next(ls); - if (check_next1(ls, '=')) return TK_NE; - else return '~'; - } - case ':': { - next(ls); - if (check_next1(ls, ':')) return TK_DBCOLON; - else return ':'; - } - case '"': case '\'': { /* short literal strings */ - read_string(ls, ls->current, seminfo); - return TK_STRING; - } - case '.': { /* '.', '..', '...', or number */ - save_and_next(ls); - if (check_next1(ls, '.')) { - if (check_next1(ls, '.')) - return TK_DOTS; /* '...' */ - else return TK_CONCAT; /* '..' */ - } - else if (!lisdigit(ls->current)) return '.'; - else return read_numeral(ls, seminfo); - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - return read_numeral(ls, seminfo); - } - case EOZ: { - return TK_EOS; - } - default: { - if (lislalpha(ls->current)) { /* identifier or reserved word? */ - TString *ts; - do { - save_and_next(ls); - } while (lislalnum(ls->current)); - ts = luaX_newstring(ls, luaZ_buffer(ls->buff), - luaZ_bufflen(ls->buff)); - seminfo->ts = ts; - if (isreserved(ts)) /* reserved word? */ - return ts->extra - 1 + FIRST_RESERVED; - else { - return TK_NAME; - } - } - else { /* single-char tokens (+ - / ...) */ - int c = ls->current; - next(ls); - return c; - } - } - } - } -} - - -void luaX_next (LexState *ls) { - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ - } - else - ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ -} - - -int luaX_lookahead (LexState *ls) { - lua_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); - return ls->lookahead.token; -} - +/* +** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "llex.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lzio.h" + + + +#define next(ls) (ls->current = zgetc(ls->z)) + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + + +/* ORDER RESERVED */ +static const char *const luaX_tokens [] = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "goto", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" +}; + + +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static l_noret lexerror (LexState *ls, const char *msg, int token); + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { + size_t newsize; + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[luaZ_bufflen(b)++] = cast(char, c); +} + + +void luaX_init (lua_State *L) { + int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ + for (i=0; iextra = cast_byte(i+1); /* reserved word */ + } +} + + +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ + lua_assert(token == cast_uchar(token)); + return luaO_pushfstring(ls->L, "'%c'", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ + return luaO_pushfstring(ls->L, "'%s'", s); + else /* names, strings, and numerals */ + return s; + } +} + + +static const char *txtToken (LexState *ls, int token) { + switch (token) { + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: + save(ls, '\0'); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); + default: + return luaX_token2str(ls, token); + } +} + + +static l_noret lexerror (LexState *ls, const char *msg, int token) { + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); + if (token) + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); +} + + +l_noret luaX_syntaxerror (LexState *ls, const char *msg) { + lexerror(ls, msg, ls->t.token); +} + + +/* +** creates a new string and anchors it in scanner's table so that +** it will not be collected until the end of the compilation +** (by that time it should be anchored somewhere) +*/ +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TValue *o; /* entry for 'str' */ + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_set(L, ls->h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ + setbvalue(o, 1); /* t[string] = true */ + luaC_checkGC(L); + } + else { /* string already present */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ + } + L->top--; /* remove string from stack */ + return ts; +} + + +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip '\n' or '\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip '\n\r' or '\r\n' */ + if (++ls->linenumber >= MAX_INT) + lexerror(ls, "chunk has too many lines", 0); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, + int firstchar) { + ls->t.token = 0; + ls->L = L; + ls->current = firstchar; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ +} + + + +/* +** ======================================================= +** LEXICAL ANALYZER +** ======================================================= +*/ + + +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; +} + + +/* +** Check whether current char is in set 'set' (with two chars) and +** saves it +*/ +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; + } + else return 0; +} + + +/* LUA_NUMBER */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2num' +** will reject ill-formed numerals. +*/ +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; + const char *expo = "Ee"; + int first = ls->current; + lua_assert(lisdigit(ls->current)); + save_and_next(ls); + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next2(ls, expo)) /* exponent part? */ + check_next2(ls, "-+"); /* optional exponent sign */ + if (lisxdigit(ls->current)) + save_and_next(ls); + else if (ls->current == '.') + save_and_next(ls); + else break; + } + save(ls, '\0'); + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } +} + + +/* +** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return +** its number of '='s; otherwise, return a negative number (-1 iff there +** are no '='s after initial bracket) +*/ +static int skip_sep (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '=') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls->current) { + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); + break; /* to avoid warnings */ + } + case ']': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd ']' */ + goto endloop; + } + break; + } + case '\n': case '\r': { + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ + break; + } + default: { + if (seminfo) save_and_next(ls); + else next(ls); + } + } + } endloop: + if (seminfo) + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); +} + + +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); +} + + +static int readhexaesc (LexState *ls) { + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while ((save_and_next(ls), lisxdigit(ls->current))) { + i++; + r = (r << 4) + luaO_hexavalue(ls->current); + esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); + } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ + return r; +} + + +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + +static int readdecesc (LexState *ls) { + int i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ + r = 10*r + ls->current - '0'; + save_and_next(ls); + } + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ + return r; +} + + +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); /* keep delimiter (for error messages) */ + while (ls->current != del) { + switch (ls->current) { + case EOZ: + lexerror(ls, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + case '\r': + lexerror(ls, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ + save_and_next(ls); /* keep '\\' for error messages */ + switch (ls->current) { + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ + case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + next(ls); /* skip the 'z' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + goto no_save; + } + default: { + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ + goto only_save; + } + } + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ + no_save: break; + } + default: + save_and_next(ls); + } + } + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); +} + + +static int llex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); + for (;;) { + switch (ls->current) { + case '\n': case '\r': { /* line breaks */ + inclinenumber(ls); + break; + } + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ + next(ls); + if (ls->current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls->current == '[') { /* long comment? */ + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); /* skip until end of line (or end of file) */ + break; + } + case '[': { /* long string or simply '[' */ + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return TK_STRING; + } + else if (sep != -1) /* '[=...' missing second bracket */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; + } + case '=': { + next(ls); + if (check_next1(ls, '=')) return TK_EQ; + else return '='; + } + case '<': { + next(ls); + if (check_next1(ls, '=')) return TK_LE; + else if (check_next1(ls, '<')) return TK_SHL; + else return '<'; + } + case '>': { + next(ls); + if (check_next1(ls, '=')) return TK_GE; + else if (check_next1(ls, '>')) return TK_SHR; + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; + else return '/'; + } + case '~': { + next(ls); + if (check_next1(ls, '=')) return TK_NE; + else return '~'; + } + case ':': { + next(ls); + if (check_next1(ls, ':')) return TK_DBCOLON; + else return ':'; + } + case '"': case '\'': { /* short literal strings */ + read_string(ls, ls->current, seminfo); + return TK_STRING; + } + case '.': { /* '.', '..', '...', or number */ + save_and_next(ls); + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ + } + else if (!lisdigit(ls->current)) return '.'; + else return read_numeral(ls, seminfo); + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + return read_numeral(ls, seminfo); + } + case EOZ: { + return TK_EOS; + } + default: { + if (lislalpha(ls->current)) { /* identifier or reserved word? */ + TString *ts; + do { + save_and_next(ls); + } while (lislalnum(ls->current)); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); + seminfo->ts = ts; + if (isreserved(ts)) /* reserved word? */ + return ts->extra - 1 + FIRST_RESERVED; + else { + return TK_NAME; + } + } + else { /* single-char tokens (+ - / ...) */ + int c = ls->current; + next(ls); + return c; + } + } + } + } +} + + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +int luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; +} + diff --git a/libs/lua/source/lmathlib.c b/libs/lua/source/lmathlib.c index 7ef7e593..446f7f58 100644 --- a/libs/lua/source/lmathlib.c +++ b/libs/lua/source/lmathlib.c @@ -1,410 +1,410 @@ -/* -** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $ -** Standard mathematical library -** See Copyright Notice in lua.h -*/ - -#define lmathlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#undef PI -#define PI (l_mathop(3.141592653589793238462643383279502884)) - - -#if !defined(l_rand) /* { */ -#if defined(LUA_USE_POSIX) -#define l_rand() random() -#define l_srand(x) srandom(x) -#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ -#else -#define l_rand() rand() -#define l_srand(x) srand(x) -#define L_RANDMAX RAND_MAX -#endif -#endif /* } */ - - -static int math_abs (lua_State *L) { - if (lua_isinteger(L, 1)) { - lua_Integer n = lua_tointeger(L, 1); - if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); - lua_pushinteger(L, n); - } - else - lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_sin (lua_State *L) { - lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_cos (lua_State *L) { - lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_tan (lua_State *L) { - lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_asin (lua_State *L) { - lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_acos (lua_State *L) { - lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_atan (lua_State *L) { - lua_Number y = luaL_checknumber(L, 1); - lua_Number x = luaL_optnumber(L, 2, 1); - lua_pushnumber(L, l_mathop(atan2)(y, x)); - return 1; -} - - -static int math_toint (lua_State *L) { - int valid; - lua_Integer n = lua_tointegerx(L, 1, &valid); - if (valid) - lua_pushinteger(L, n); - else { - luaL_checkany(L, 1); - lua_pushnil(L); /* value is not convertible to integer */ - } - return 1; -} - - -static void pushnumint (lua_State *L, lua_Number d) { - lua_Integer n; - if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ - lua_pushinteger(L, n); /* result is integer */ - else - lua_pushnumber(L, d); /* result is float */ -} - - -static int math_floor (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own floor */ - else { - lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; -} - - -static int math_ceil (lua_State *L) { - if (lua_isinteger(L, 1)) - lua_settop(L, 1); /* integer is its own ceil */ - else { - lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); - pushnumint(L, d); - } - return 1; -} - - -static int math_fmod (lua_State *L) { - if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { - lua_Integer d = lua_tointeger(L, 2); - if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ - luaL_argcheck(L, d != 0, 2, "zero"); - lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ - } - else - lua_pushinteger(L, lua_tointeger(L, 1) % d); - } - else - lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); - return 1; -} - - -/* -** next function does not use 'modf', avoiding problems with 'double*' -** (which is not compatible with 'float*') when lua_Number is not -** 'double'. -*/ -static int math_modf (lua_State *L) { - if (lua_isinteger(L ,1)) { - lua_settop(L, 1); /* number is its own integer part */ - lua_pushnumber(L, 0); /* no fractional part */ - } - else { - lua_Number n = luaL_checknumber(L, 1); - /* integer part (rounds toward zero) */ - lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); - pushnumint(L, ip); - /* fractional part (test needed for inf/-inf) */ - lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); - } - return 2; -} - - -static int math_sqrt (lua_State *L) { - lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); - return 1; -} - - -static int math_ult (lua_State *L) { - lua_Integer a = luaL_checkinteger(L, 1); - lua_Integer b = luaL_checkinteger(L, 2); - lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); - return 1; -} - -static int math_log (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number res; - if (lua_isnoneornil(L, 2)) - res = l_mathop(log)(x); - else { - lua_Number base = luaL_checknumber(L, 2); -#if !defined(LUA_USE_C89) - if (base == l_mathop(2.0)) - res = l_mathop(log2)(x); else -#endif - if (base == l_mathop(10.0)) - res = l_mathop(log10)(x); - else - res = l_mathop(log)(x)/l_mathop(log)(base); - } - lua_pushnumber(L, res); - return 1; -} - -static int math_exp (lua_State *L) { - lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); - return 1; -} - -static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); - return 1; -} - - -static int math_min (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imin = 1; /* index of current minimum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, i, imin, LUA_OPLT)) - imin = i; - } - lua_pushvalue(L, imin); - return 1; -} - - -static int math_max (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int imax = 1; /* index of current maximum value */ - int i; - luaL_argcheck(L, n >= 1, 1, "value expected"); - for (i = 2; i <= n; i++) { - if (lua_compare(L, imax, i, LUA_OPLT)) - imax = i; - } - lua_pushvalue(L, imax); - return 1; -} - -/* -** This function uses 'double' (instead of 'lua_Number') to ensure that -** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' -** will keep full precision (ensuring that 'r' is always less than 1.0.) -*/ -static int math_random (lua_State *L) { - lua_Integer low, up; - double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); - switch (lua_gettop(L)) { /* check number of arguments */ - case 0: { /* no arguments */ - lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ - return 1; - } - case 1: { /* only upper limit */ - low = 1; - up = luaL_checkinteger(L, 1); - break; - } - case 2: { /* lower and upper limits */ - low = luaL_checkinteger(L, 1); - up = luaL_checkinteger(L, 2); - break; - } - default: return luaL_error(L, "wrong number of arguments"); - } - /* random integer in the interval [low, up] */ - luaL_argcheck(L, low <= up, 1, "interval is empty"); - luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, - "interval too large"); - r *= (double)(up - low) + 1.0; - lua_pushinteger(L, (lua_Integer)r + low); - return 1; -} - - -static int math_randomseed (lua_State *L) { - l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); - (void)l_rand(); /* discard first value to avoid undesirable correlations */ - return 0; -} - - -static int math_type (lua_State *L) { - if (lua_type(L, 1) == LUA_TNUMBER) { - if (lua_isinteger(L, 1)) - lua_pushliteral(L, "integer"); - else - lua_pushliteral(L, "float"); - } - else { - luaL_checkany(L, 1); - lua_pushnil(L); - } - return 1; -} - - -/* -** {================================================================== -** Deprecated functions (for compatibility only) -** =================================================================== -*/ -#if defined(LUA_COMPAT_MATHLIB) - -static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); - return 1; -} - -static int math_pow (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number y = luaL_checknumber(L, 2); - lua_pushnumber(L, l_mathop(pow)(x, y)); - return 1; -} - -static int math_frexp (lua_State *L) { - int e; - lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); - lua_pushinteger(L, e); - return 2; -} - -static int math_ldexp (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - int ep = (int)luaL_checkinteger(L, 2); - lua_pushnumber(L, l_mathop(ldexp)(x, ep)); - return 1; -} - -static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); - return 1; -} - -#endif -/* }================================================================== */ - - - -static const luaL_Reg mathlib[] = { - {"abs", math_abs}, - {"acos", math_acos}, - {"asin", math_asin}, - {"atan", math_atan}, - {"ceil", math_ceil}, - {"cos", math_cos}, - {"deg", math_deg}, - {"exp", math_exp}, - {"tointeger", math_toint}, - {"floor", math_floor}, - {"fmod", math_fmod}, - {"ult", math_ult}, - {"log", math_log}, - {"max", math_max}, - {"min", math_min}, - {"modf", math_modf}, - {"rad", math_rad}, - {"random", math_random}, - {"randomseed", math_randomseed}, - {"sin", math_sin}, - {"sqrt", math_sqrt}, - {"tan", math_tan}, - {"type", math_type}, -#if defined(LUA_COMPAT_MATHLIB) - {"atan2", math_atan}, - {"cosh", math_cosh}, - {"sinh", math_sinh}, - {"tanh", math_tanh}, - {"pow", math_pow}, - {"frexp", math_frexp}, - {"ldexp", math_ldexp}, - {"log10", math_log10}, -#endif - /* placeholders */ - {"pi", NULL}, - {"huge", NULL}, - {"maxinteger", NULL}, - {"mininteger", NULL}, - {NULL, NULL} -}; - - -/* -** Open math library -*/ -LUAMOD_API int luaopen_math (lua_State *L) { - luaL_newlib(L, mathlib); - lua_pushnumber(L, PI); - lua_setfield(L, -2, "pi"); - lua_pushnumber(L, (lua_Number)HUGE_VAL); - lua_setfield(L, -2, "huge"); - lua_pushinteger(L, LUA_MAXINTEGER); - lua_setfield(L, -2, "maxinteger"); - lua_pushinteger(L, LUA_MININTEGER); - lua_setfield(L, -2, "mininteger"); - return 1; -} - +/* +** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#undef PI +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +#if !defined(l_rand) /* { */ +#if defined(LUA_USE_POSIX) +#define l_rand() random() +#define l_srand(x) srandom(x) +#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ +#else +#define l_rand() rand() +#define l_srand(x) srand(x) +#define L_RANDMAX RAND_MAX +#endif +#endif /* } */ + + +static int math_abs (lua_State *L) { + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sin (lua_State *L) { + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_cos (lua_State *L) { + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tan (lua_State *L) { + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_asin (lua_State *L) { + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_acos (lua_State *L) { + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_atan (lua_State *L) { + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); + return 1; +} + + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (valid) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ + } + return 1; +} + + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ +} + + +static int math_floor (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_fmod (lua_State *L) { + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); + return 1; +} + + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ +static int math_modf (lua_State *L) { + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } + return 2; +} + + +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); + return 1; +} + + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); + return 1; +} + +static int math_log (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = l_mathop(log)(x); + else { + lua_Number base = luaL_checknumber(L, 2); +#if !defined(LUA_USE_C89) + if (base == l_mathop(2.0)) + res = l_mathop(log2)(x); else +#endif + if (base == l_mathop(10.0)) + res = l_mathop(log10)(x); + else + res = l_mathop(log)(x)/l_mathop(log)(base); + } + lua_pushnumber(L, res); + return 1; +} + +static int math_exp (lua_State *L) { + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); + return 1; +} + +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); + return 1; +} + + +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imin = 1; /* index of current minimum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; + } + lua_pushvalue(L, imin); + return 1; +} + + +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int imax = 1; /* index of current maximum value */ + int i; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; + } + lua_pushvalue(L, imax); + return 1; +} + +/* +** This function uses 'double' (instead of 'lua_Number') to ensure that +** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' +** will keep full precision (ensuring that 'r' is always less than 1.0.) +*/ +static int math_random (lua_State *L) { + lua_Integer low, up; + double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ + return 1; + } + case 1: { /* only upper limit */ + low = 1; + up = luaL_checkinteger(L, 1); + break; + } + case 2: { /* lower and upper limits */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + "interval too large"); + r *= (double)(up - low) + 1.0; + lua_pushinteger(L, (lua_Integer)r + low); + return 1; +} + + +static int math_randomseed (lua_State *L) { + l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); + (void)l_rand(); /* discard first value to avoid undesirable correlations */ + return 0; +} + + +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); + else + lua_pushliteral(L, "float"); + } + else { + luaL_checkany(L, 1); + lua_pushnil(L); + } + return 1; +} + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + +static const luaL_Reg mathlib[] = { + {"abs", math_abs}, + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, + {"tointeger", math_toint}, + {"floor", math_floor}, + {"fmod", math_fmod}, + {"ult", math_ult}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, + {NULL, NULL} +}; + + +/* +** Open math library +*/ +LUAMOD_API int luaopen_math (lua_State *L) { + luaL_newlib(L, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, (lua_Number)HUGE_VAL); + lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); + return 1; +} + diff --git a/libs/lua/source/lmem.c b/libs/lua/source/lmem.c index 0241cc3b..6d969bd1 100644 --- a/libs/lua/source/lmem.c +++ b/libs/lua/source/lmem.c @@ -1,100 +1,100 @@ -/* -** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - -#define lmem_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - - -/* -** About the realloc function: -** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); -** ('osize' is the old size, 'nsize' is the new size) -** -** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no -** matter 'x'). -** -** * frealloc(ud, p, x, 0) frees the block 'p' -** (in this specific case, frealloc must return NULL); -** particularly, frealloc(ud, NULL, 0, 0) does nothing -** (which is equivalent to free(NULL) in ISO C) -** -** frealloc returns NULL if it cannot create or reallocate the area -** (any reallocation to an equal or smaller size cannot fail!) -*/ - - - -#define MINSIZEARRAY 4 - - -void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - int limit, const char *what) { - void *newblock; - int newsize; - if (*size >= limit/2) { /* cannot double it? */ - if (*size >= limit) /* cannot grow even a little? */ - luaG_runerror(L, "too many %s (limit is %d)", what, limit); - newsize = limit; /* still have at least one free place */ - } - else { - newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - } - newblock = luaM_reallocv(L, block, *size, newsize, size_elems); - *size = newsize; /* update only when everything else is OK */ - return newblock; -} - - -l_noret luaM_toobig (lua_State *L) { - luaG_runerror(L, "memory allocation error: block too big"); -} - - - -/* -** generic allocation routine. -*/ -void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { - void *newblock; - global_State *g = G(L); - size_t realosize = (block) ? osize : 0; - lua_assert((realosize == 0) == (block == NULL)); -#if defined(HARDMEMTESTS) - if (nsize > realosize && g->gcrunning) - luaC_fullgc(L, 1); /* force a GC whenever possible */ -#endif - newblock = (*g->frealloc)(g->ud, block, osize, nsize); - if (newblock == NULL && nsize > 0) { - lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ - if (g->version) { /* is state fully built? */ - luaC_fullgc(L, 1); /* try to free some memory... */ - newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ - } - if (newblock == NULL) - luaD_throw(L, LUA_ERRMEM); - } - lua_assert((nsize == 0) == (newblock == NULL)); - g->GCdebt = (g->GCdebt + nsize) - realosize; - return newblock; -} - +/* +** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#define lmem_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" + + + +/* +** About the realloc function: +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); +** ('osize' is the old size, 'nsize' is the new size) +** +** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no +** matter 'x'). +** +** * frealloc(ud, p, x, 0) frees the block 'p' +** (in this specific case, frealloc must return NULL); +** particularly, frealloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ISO C) +** +** frealloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) +*/ + + + +#define MINSIZEARRAY 4 + + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *what) { + void *newblock; + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, "too many %s (limit is %d)", what, limit); + newsize = limit; /* still have at least one free place */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); + *size = newsize; /* update only when everything else is OK */ + return newblock; +} + + +l_noret luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); +} + + + +/* +** generic allocation routine. +*/ +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; + global_State *g = G(L); + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); +#if defined(HARDMEMTESTS) + if (nsize > realosize && g->gcrunning) + luaC_fullgc(L, 1); /* force a GC whenever possible */ +#endif + newblock = (*g->frealloc)(g->ud, block, osize, nsize); + if (newblock == NULL && nsize > 0) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->version) { /* is state fully built? */ + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + if (newblock == NULL) + luaD_throw(L, LUA_ERRMEM); + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->GCdebt = (g->GCdebt + nsize) - realosize; + return newblock; +} + diff --git a/libs/lua/source/loadlib.c b/libs/lua/source/loadlib.c index 45f44d32..9dc11f20 100644 --- a/libs/lua/source/loadlib.c +++ b/libs/lua/source/loadlib.c @@ -1,790 +1,790 @@ -/* -** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -** -** This module contains an implementation of loadlib for Unix systems -** that have dlfcn, an implementation for Windows, and a stub for other -** systems. -*/ - -#define loadlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** LUA_IGMARK is a mark to ignore all before it when building the -** luaopen_ function name. -*/ -#if !defined (LUA_IGMARK) -#define LUA_IGMARK "-" -#endif - - -/* -** LUA_CSUBSEP is the character that replaces dots in submodule names -** when searching for a C loader. -** LUA_LSUBSEP is the character that replaces dots in submodule names -** when searching for a Lua loader. -*/ -#if !defined(LUA_CSUBSEP) -#define LUA_CSUBSEP LUA_DIRSEP -#endif - -#if !defined(LUA_LSUBSEP) -#define LUA_LSUBSEP LUA_DIRSEP -#endif - - -/* prefix for open functions in C libraries */ -#define LUA_POF "luaopen_" - -/* separator for open functions in C libraries */ -#define LUA_OFSEP "_" - - -/* -** unique key for table in the registry that keeps handles -** for all loaded C libraries -*/ -static const int CLIBS = 0; - -#define LIB_FAIL "open" - - -#define setprogdir(L) ((void)0) - - -/* -** system-dependent functions -*/ - -/* -** unload library 'lib' -*/ -static void lsys_unloadlib (void *lib); - -/* -** load C library in file 'path'. If 'seeglb', load with all names in -** the library global. -** Returns the library; in case of error, returns NULL plus an -** error string in the stack. -*/ -static void *lsys_load (lua_State *L, const char *path, int seeglb); - -/* -** Try to find a function named 'sym' in library 'lib'. -** Returns the function; in case of error, returns NULL plus an -** error string in the stack. -*/ -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); - - - - -#if defined(LUA_USE_DLOPEN) /* { */ -/* -** {======================================================================== -** This is an implementation of loadlib based on the dlfcn interface. -** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -** as an emulation layer on top of native functions. -** ========================================================================= -*/ - -#include - -/* -** Macro to convert pointer-to-void* to pointer-to-function. This cast -** is undefined according to ISO C, but POSIX assumes that it works. -** (The '__extension__' in gnu compilers is only to avoid warnings.) -*/ -#if defined(__GNUC__) -#define cast_func(p) (__extension__ (lua_CFunction)(p)) -#else -#define cast_func(p) ((lua_CFunction)(p)) -#endif - - -static void lsys_unloadlib (void *lib) { - dlclose(lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); - if (lib == NULL) lua_pushstring(L, dlerror()); - return lib; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = cast_func(dlsym(lib, sym)); - if (f == NULL) lua_pushstring(L, dlerror()); - return f; -} - -/* }====================================================== */ - - - -#elif defined(LUA_DL_DLL) /* }{ */ -/* -** {====================================================================== -** This is an implementation of loadlib for Windows using native functions. -** ======================================================================= -*/ - -#include - - -/* -** optional flags for LoadLibraryEx -*/ -#if !defined(LUA_LLE_FLAGS) -#define LUA_LLE_FLAGS 0 -#endif - - -#undef setprogdir - - -/* -** Replace in the path (on the top of the stack) any occurrence -** of LUA_EXEC_DIR with the executable's path. -*/ -static void setprogdir (lua_State *L) { - char buff[MAX_PATH + 1]; - char *lb; - DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ - if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) - luaL_error(L, "unable to get ModuleFileName"); - else { - *lb = '\0'; /* cut name on the last '\\' to get the path */ - luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); - lua_remove(L, -2); /* remove original string */ - } -} - - - - -static void pusherror (lua_State *L) { - int error = GetLastError(); - char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); -} - -static void lsys_unloadlib (void *lib) { - FreeLibrary((HMODULE)lib); -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); - (void)(seeglb); /* not used: symbols are 'global' by default */ - if (lib == NULL) pusherror(L); - return lib; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); - if (f == NULL) pusherror(L); - return f; -} - -/* }====================================================== */ - - -#else /* }{ */ -/* -** {====================================================== -** Fallback for other systems -** ======================================================= -*/ - -#undef LIB_FAIL -#define LIB_FAIL "absent" - - -#define DLMSG "dynamic libraries not enabled; check your Lua installation" - - -static void lsys_unloadlib (void *lib) { - (void)(lib); /* not used */ -} - - -static void *lsys_load (lua_State *L, const char *path, int seeglb) { - (void)(path); (void)(seeglb); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - - -static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { - (void)(lib); (void)(sym); /* not used */ - lua_pushliteral(L, DLMSG); - return NULL; -} - -/* }====================================================== */ -#endif /* } */ - - -/* -** {================================================================== -** Set Paths -** =================================================================== -*/ - -/* -** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment -** variables that Lua check to set its paths. -*/ -#if !defined(LUA_PATH_VAR) -#define LUA_PATH_VAR "LUA_PATH" -#endif - -#if !defined(LUA_CPATH_VAR) -#define LUA_CPATH_VAR "LUA_CPATH" -#endif - - -#define AUXMARK "\1" /* auxiliary mark */ - - -/* -** return registry.LUA_NOENV as a boolean -*/ -static int noenv (lua_State *L) { - int b; - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); - b = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - return b; -} - - -/* -** Set a path -*/ -static void setpath (lua_State *L, const char *fieldname, - const char *envname, - const char *dft) { - const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); - const char *path = getenv(nver); /* use versioned name */ - if (path == NULL) /* no environment variable? */ - path = getenv(envname); /* try unversioned name */ - if (path == NULL || noenv(L)) /* no environment variable? */ - lua_pushstring(L, dft); /* use default */ - else { - /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, - LUA_PATH_SEP AUXMARK LUA_PATH_SEP); - luaL_gsub(L, path, AUXMARK, dft); - lua_remove(L, -2); /* remove result from 1st 'gsub' */ - } - setprogdir(L); - lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ - lua_pop(L, 1); /* pop versioned variable name */ -} - -/* }================================================================== */ - - -/* -** return registry.CLIBS[path] -*/ -static void *checkclib (lua_State *L, const char *path) { - void *plib; - lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); - lua_getfield(L, -1, path); - plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ - lua_pop(L, 2); /* pop CLIBS table and 'plib' */ - return plib; -} - - -/* -** registry.CLIBS[path] = plib -- for queries -** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries -*/ -static void addtoclib (lua_State *L, const char *path, void *plib) { - lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); - lua_pushlightuserdata(L, plib); - lua_pushvalue(L, -1); - lua_setfield(L, -3, path); /* CLIBS[path] = plib */ - lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ - lua_pop(L, 1); /* pop CLIBS table */ -} - - -/* -** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib -** handles in list CLIBS -*/ -static int gctm (lua_State *L) { - lua_Integer n = luaL_len(L, 1); - for (; n >= 1; n--) { /* for each handle, in reverse order */ - lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - lsys_unloadlib(lua_touserdata(L, -1)); - lua_pop(L, 1); /* pop handle */ - } - return 0; -} - - - -/* error codes for 'lookforfunc' */ -#define ERRLIB 1 -#define ERRFUNC 2 - -/* -** Look for a C function named 'sym' in a dynamically loaded library -** 'path'. -** First, check whether the library is already loaded; if not, try -** to load it. -** Then, if 'sym' is '*', return true (as library has been loaded). -** Otherwise, look for symbol 'sym' in the library and push a -** C function with that symbol. -** Return 0 and 'true' or a function in the stack; in case of -** errors, return an error code and an error message in the stack. -*/ -static int lookforfunc (lua_State *L, const char *path, const char *sym) { - void *reg = checkclib(L, path); /* check loaded C libraries */ - if (reg == NULL) { /* must load library? */ - reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ - if (reg == NULL) return ERRLIB; /* unable to load library */ - addtoclib(L, path, reg); - } - if (*sym == '*') { /* loading only library (no function)? */ - lua_pushboolean(L, 1); /* return 'true' */ - return 0; /* no errors */ - } - else { - lua_CFunction f = lsys_sym(L, reg, sym); - if (f == NULL) - return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function */ - return 0; /* no errors */ - } -} - - -static int ll_loadlib (lua_State *L) { - const char *path = luaL_checkstring(L, 1); - const char *init = luaL_checkstring(L, 2); - int stat = lookforfunc(L, path, init); - if (stat == 0) /* no errors? */ - return 1; /* return the loaded function */ - else { /* error; error message is on stack top */ - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); - return 3; /* return nil, error message, and where */ - } -} - - - -/* -** {====================================================== -** 'require' function -** ======================================================= -*/ - - -static int readable (const char *filename) { - FILE *f = fopen(filename, "r"); /* try to open file */ - if (f == NULL) return 0; /* open failed */ - fclose(f); - return 1; -} - - -static const char *pushnexttemplate (lua_State *L, const char *path) { - const char *l; - while (*path == *LUA_PATH_SEP) path++; /* skip separators */ - if (*path == '\0') return NULL; /* no more templates */ - l = strchr(path, *LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path + strlen(path); - lua_pushlstring(L, path, l - path); /* template */ - return l; -} - - -static const char *searchpath (lua_State *L, const char *name, - const char *path, - const char *sep, - const char *dirsep) { - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - if (*sep != '\0') /* non-empty separator? */ - name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ - while ((path = pushnexttemplate(L, path)) != NULL) { - const char *filename = luaL_gsub(L, lua_tostring(L, -1), - LUA_PATH_MARK, name); - lua_remove(L, -2); /* remove path template */ - if (readable(filename)) /* does file exist and is readable? */ - return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file '%s'", filename); - lua_remove(L, -2); /* remove file name */ - luaL_addvalue(&msg); /* concatenate error msg. entry */ - } - luaL_pushresult(&msg); /* create error message */ - return NULL; /* not found */ -} - - -static int ll_searchpath (lua_State *L) { - const char *f = searchpath(L, luaL_checkstring(L, 1), - luaL_checkstring(L, 2), - luaL_optstring(L, 3, "."), - luaL_optstring(L, 4, LUA_DIRSEP)); - if (f != NULL) return 1; - else { /* error message is on top of the stack */ - lua_pushnil(L); - lua_insert(L, -2); - return 2; /* return nil + error message */ - } -} - - -static const char *findfile (lua_State *L, const char *name, - const char *pname, - const char *dirsep) { - const char *path; - lua_getfield(L, lua_upvalueindex(1), pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, "'package.%s' must be a string", pname); - return searchpath(L, name, path, ".", dirsep); -} - - -static int checkload (lua_State *L, int stat, const char *filename) { - if (stat) { /* module loaded successfully? */ - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; /* return open function and file name */ - } - else - return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); -} - - -static int searcher_Lua (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path", LUA_LSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); -} - - -/* -** Try to find a load function for module 'modname' at file 'filename'. -** First, change '.' to '_' in 'modname'; then, if 'modname' has -** the form X-Y (that is, it has an "ignore mark"), build a function -** name "luaopen_X" and look for it. (For compatibility, if that -** fails, it also tries "luaopen_Y".) If there is no ignore mark, -** look for a function named "luaopen_modname". -*/ -static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *openfunc; - const char *mark; - modname = luaL_gsub(L, modname, ".", LUA_OFSEP); - mark = strchr(modname, *LUA_IGMARK); - if (mark) { - int stat; - openfunc = lua_pushlstring(L, modname, mark - modname); - openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); - stat = lookforfunc(L, filename, openfunc); - if (stat != ERRFUNC) return stat; - modname = mark + 1; /* else go ahead and try old-style name */ - } - openfunc = lua_pushfstring(L, LUA_POF"%s", modname); - return lookforfunc(L, filename, openfunc); -} - - -static int searcher_C (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* module not found in this path */ - return checkload(L, (loadfunc(L, filename, name) == 0), filename); -} - - -static int searcher_Croot (lua_State *L) { - const char *filename; - const char *name = luaL_checkstring(L, 1); - const char *p = strchr(name, '.'); - int stat; - if (p == NULL) return 0; /* is root */ - lua_pushlstring(L, name, p - name); - filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); - if (filename == NULL) return 1; /* root not found */ - if ((stat = loadfunc(L, filename, name)) != 0) { - if (stat != ERRFUNC) - return checkload(L, 0, filename); /* real error */ - else { /* open function not found */ - lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); - return 1; - } - } - lua_pushstring(L, filename); /* will be 2nd argument to module */ - return 2; -} - - -static int searcher_preload (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ - lua_pushfstring(L, "\n\tno field package.preload['%s']", name); - return 1; -} - - -static void findloader (lua_State *L, const char *name) { - int i; - luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); - /* push 'package.searchers' to index 3 in the stack */ - if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) - luaL_error(L, "'package.searchers' must be a table"); - /* iterate over available searchers to find a loader */ - for (i = 1; ; i++) { - if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ - lua_pop(L, 1); /* remove nil */ - luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); - } - lua_pushstring(L, name); - lua_call(L, 1, 2); /* call it */ - if (lua_isfunction(L, -2)) /* did it find a loader? */ - return; /* module loader found */ - else if (lua_isstring(L, -2)) { /* searcher returned error message? */ - lua_pop(L, 1); /* remove extra return */ - luaL_addvalue(&msg); /* concatenate error message */ - } - else - lua_pop(L, 2); /* remove both returns */ - } -} - - -static int ll_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_settop(L, 1); /* LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_getfield(L, 2, name); /* LOADED[name] */ - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded */ - /* else must load package */ - lua_pop(L, 1); /* remove 'getfield' result */ - findloader(L, name); - lua_pushstring(L, name); /* pass name as argument to module loader */ - lua_insert(L, -2); /* name is 1st argument (before search data) */ - lua_call(L, 2, 1); /* run loader to load module */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* LOADED[name] = returned value */ - if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ - lua_pushboolean(L, 1); /* use true as result */ - lua_pushvalue(L, -1); /* extra copy to be returned */ - lua_setfield(L, 2, name); /* LOADED[name] = true */ - } - return 1; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** 'module' function -** ======================================================= -*/ -#if defined(LUA_COMPAT_MODULE) - -/* -** changes the environment variable of calling function -*/ -static void set_env (lua_State *L) { - lua_Debug ar; - if (lua_getstack(L, 1, &ar) == 0 || - lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ - lua_iscfunction(L, -1)) - luaL_error(L, "'module' not called from a Lua function"); - lua_pushvalue(L, -2); /* copy new environment table to top */ - lua_setupvalue(L, -2, 1); - lua_pop(L, 1); /* remove function */ -} - - -static void dooptions (lua_State *L, int n) { - int i; - for (i = 2; i <= n; i++) { - if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ - lua_pushvalue(L, i); /* get option (a function) */ - lua_pushvalue(L, -2); /* module */ - lua_call(L, 1, 0); - } - } -} - - -static void modinit (lua_State *L, const char *modname) { - const char *dot; - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_M"); /* module._M = module */ - lua_pushstring(L, modname); - lua_setfield(L, -2, "_NAME"); - dot = strrchr(modname, '.'); /* look for last dot in module name */ - if (dot == NULL) dot = modname; - else dot++; - /* set _PACKAGE as package name (full module name minus last part) */ - lua_pushlstring(L, modname, dot - modname); - lua_setfield(L, -2, "_PACKAGE"); -} - - -static int ll_module (lua_State *L) { - const char *modname = luaL_checkstring(L, 1); - int lastarg = lua_gettop(L); /* last parameter */ - luaL_pushmodule(L, modname, 1); /* get/create module table */ - /* check whether table already has a _NAME field */ - if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) - lua_pop(L, 1); /* table is an initialized module */ - else { /* no; initialize it */ - lua_pop(L, 1); - modinit(L, modname); - } - lua_pushvalue(L, -1); - set_env(L); - dooptions(L, lastarg); - return 1; -} - - -static int ll_seeall (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - if (!lua_getmetatable(L, 1)) { - lua_createtable(L, 0, 1); /* create new metatable */ - lua_pushvalue(L, -1); - lua_setmetatable(L, 1); - } - lua_pushglobaltable(L); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - return 0; -} - -#endif -/* }====================================================== */ - - - -static const luaL_Reg pk_funcs[] = { - {"loadlib", ll_loadlib}, - {"searchpath", ll_searchpath}, -#if defined(LUA_COMPAT_MODULE) - {"seeall", ll_seeall}, -#endif - /* placeholders */ - {"preload", NULL}, - {"cpath", NULL}, - {"path", NULL}, - {"searchers", NULL}, - {"loaded", NULL}, - {NULL, NULL} -}; - - -static const luaL_Reg ll_funcs[] = { -#if defined(LUA_COMPAT_MODULE) - {"module", ll_module}, -#endif - {"require", ll_require}, - {NULL, NULL} -}; - - -static void createsearcherstable (lua_State *L) { - static const lua_CFunction searchers[] = - {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - int i; - /* create 'searchers' table */ - lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with predefined searchers */ - for (i=0; searchers[i] != NULL; i++) { - lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ - lua_pushcclosure(L, searchers[i], 1); - lua_rawseti(L, -2, i+1); - } -#if defined(LUA_COMPAT_LOADERS) - lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ - lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ -#endif - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ -} - - -/* -** create table CLIBS to keep track of loaded C libraries, -** setting a finalizer to close all libraries when closing state. -*/ -static void createclibstable (lua_State *L) { - lua_newtable(L); /* create CLIBS table */ - lua_createtable(L, 0, 1); /* create metatable for CLIBS */ - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ - lua_setmetatable(L, -2); - lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ -} - - -LUAMOD_API int luaopen_package (lua_State *L) { - createclibstable(L); - luaL_newlib(L, pk_funcs); /* create 'package' table */ - createsearcherstable(L); - /* set paths */ - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); - setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); - /* store config information */ - lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" - LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); - lua_setfield(L, -2, "config"); - /* set field 'loaded' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); - lua_setfield(L, -2, "loaded"); - /* set field 'preload' */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); - lua_setfield(L, -2, "preload"); - lua_pushglobaltable(L); - lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ - luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ - lua_pop(L, 1); /* pop global table */ - return 1; /* return 'package' table */ -} - +/* +** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Windows, and a stub for other +** systems. +*/ + +#define loadlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + +/* +** LUA_CSUBSEP is the character that replaces dots in submodule names +** when searching for a C loader. +** LUA_LSUBSEP is the character that replaces dots in submodule names +** when searching for a Lua loader. +*/ +#if !defined(LUA_CSUBSEP) +#define LUA_CSUBSEP LUA_DIRSEP +#endif + +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + +/* +** unique key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const int CLIBS = 0; + +#define LIB_FAIL "open" + + +#define setprogdir(L) ((void)0) + + +/* +** system-dependent functions +*/ + +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); + + + + +#if defined(LUA_USE_DLOPEN) /* { */ +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(LUA_DL_DLL) /* }{ */ +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +/* +** optional flags for LoadLibraryEx +*/ +#if !defined(LUA_LLE_FLAGS) +#define LUA_LLE_FLAGS 0 +#endif + + +#undef setprogdir + + +/* +** Replace in the path (on the top of the stack) any occurrence +** of LUA_EXEC_DIR with the executable's path. +*/ +static void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; /* cut name on the last '\\' to get the path */ + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); + lua_remove(L, -2); /* remove original string */ + } +} + + + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void lsys_unloadlib (void *lib) { + FreeLibrary((HMODULE)lib); +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); + (void)(seeglb); /* not used: symbols are 'global' by default */ + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + +#else /* }{ */ +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + + +static void lsys_unloadlib (void *lib) { + (void)(lib); /* not used */ +} + + +static void *lsys_load (lua_State *L, const char *path, int seeglb) { + (void)(path); (void)(seeglb); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + + +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + (void)(lib); (void)(sym); /* not used */ + lua_pushliteral(L, DLMSG); + return NULL; +} + +/* }====================================================== */ +#endif /* } */ + + +/* +** {================================================================== +** Set Paths +** =================================================================== +*/ + +/* +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" +#endif + +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" +#endif + + +#define AUXMARK "\1" /* auxiliary mark */ + + +/* +** return registry.LUA_NOENV as a boolean +*/ +static int noenv (lua_State *L) { + int b; + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + b = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + return b; +} + + +/* +** Set a path +*/ +static void setpath (lua_State *L, const char *fieldname, + const char *envname, + const char *dft) { + const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); + const char *path = getenv(nver); /* use versioned name */ + if (path == NULL) /* no environment variable? */ + path = getenv(envname); /* try unversioned name */ + if (path == NULL || noenv(L)) /* no environment variable? */ + lua_pushstring(L, dft); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); + luaL_gsub(L, path, AUXMARK, dft); + lua_remove(L, -2); /* remove result from 1st 'gsub' */ + } + setprogdir(L); + lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ + lua_pop(L, 1); /* pop versioned variable name */ +} + +/* }================================================================== */ + + +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { + void *plib; + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ + return plib; +} + + +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + +/* +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib +** handles in list CLIBS +*/ +static int gctm (lua_State *L) { + lua_Integer n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + lsys_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } + return 0; +} + + + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ + if (reg == NULL) return ERRLIB; /* unable to load library */ + addtoclib(L, path, reg); + } + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } + else { + lua_CFunction f = lsys_sym(L, reg, sym); + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); /* else create new function */ + return 0; /* no errors */ + } +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + int stat = lookforfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } +} + + + +/* +** {====================================================== +** 'require' function +** ======================================================= +*/ + + +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *searchpath (lua_State *L, const char *name, + const char *path, + const char *sep, + const char *dirsep) { + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + if (*sep != '\0') /* non-empty separator? */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file '%s'", filename); + lua_remove(L, -2); /* remove file name */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ + } + luaL_pushresult(&msg); /* create error message */ + return NULL; /* not found */ +} + + +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + lua_pushnil(L); + lua_insert(L, -2); + return 2; /* return nil + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname, + const char *dirsep) { + const char *path; + lua_getfield(L, lua_upvalueindex(1), pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, "'package.%s' must be a string", pname); + return searchpath(L, name, path, ".", dirsep); +} + + +static int checkload (lua_State *L, int stat, const char *filename) { + if (stat) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); +} + + +static int searcher_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path", LUA_LSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); +} + + +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ +static int loadfunc (lua_State *L, const char *filename, const char *modname) { + const char *openfunc; + const char *mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) { + int stat; + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); +} + + +static int searcher_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); +} + + +static int searcher_Croot (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); + if (filename == NULL) return 1; /* root not found */ + if ((stat = loadfunc(L, filename, name)) != 0) { + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else { /* open function not found */ + lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); + return 1; + } + } + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; +} + + +static int searcher_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; +} + + +static void findloader (lua_State *L, const char *name) { + int i; + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); + /* iterate over available searchers to find a loader */ + for (i = 1; ; i++) { + if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find a loader? */ + return; /* module loader found */ + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else + lua_pop(L, 2); /* remove both returns */ + } +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_pushstring(L, name); /* pass name as argument to module loader */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_call(L, 2, 1); /* run loader to load module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + return 1; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +/* +** changes the environment variable of calling function +*/ +static void set_env (lua_State *L) { + lua_Debug ar; + if (lua_getstack(L, 1, &ar) == 0 || + lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ + lua_iscfunction(L, -1)) + luaL_error(L, "'module' not called from a Lua function"); + lua_pushvalue(L, -2); /* copy new environment table to top */ + lua_setupvalue(L, -2, 1); + lua_pop(L, 1); /* remove function */ +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + int lastarg = lua_gettop(L); /* last parameter */ + luaL_pushmodule(L, modname, 1); /* get/create module table */ + /* check whether table already has a _NAME field */ + if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) + lua_pop(L, 1); /* table is an initialized module */ + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + set_env(L); + dooptions(L, lastarg); + return 1; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushglobaltable(L); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; +} + +#endif +/* }====================================================== */ + + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, +#if defined(LUA_COMPAT_MODULE) + {"seeall", ll_seeall}, +#endif + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { +#if defined(LUA_COMPAT_MODULE) + {"module", ll_module}, +#endif + {"require", ll_require}, + {NULL, NULL} +}; + + +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; + int i; + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i=0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i+1); + } +#if defined(LUA_COMPAT_LOADERS) + lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ + lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ +#endif + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ +} + + +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); + lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ + createsearcherstable(L); + /* set paths */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); + lua_setfield(L, -2, "config"); + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ +} + diff --git a/libs/lua/source/lobject.c b/libs/lua/source/lobject.c index 2218c8cd..ef1cb848 100644 --- a/libs/lua/source/lobject.c +++ b/libs/lua/source/lobject.c @@ -1,522 +1,522 @@ -/* -** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $ -** Some generic functions over Lua objects -** See Copyright Notice in lua.h -*/ - -#define lobject_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lctype.h" -#include "ldebug.h" -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "lvm.h" - - - -LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; - - -/* -** converts an integer to a "floating point byte", represented as -** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if -** eeeee != 0 and (xxx) otherwise. -*/ -int luaO_int2fb (unsigned int x) { - int e = 0; /* exponent */ - if (x < 8) return x; - while (x >= (8 << 4)) { /* coarse steps */ - x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ - e += 4; - } - while (x >= (8 << 1)) { /* fine steps */ - x = (x + 1) >> 1; /* x = ceil(x / 2) */ - e++; - } - return ((e+1) << 3) | (cast_int(x) - 8); -} - - -/* converts back */ -int luaO_fb2int (int x) { - return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); -} - - -/* -** Computes ceil(log2(x)) -*/ -int luaO_ceillog2 (unsigned int x) { - static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 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, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - }; - int l = 0; - x--; - while (x >= 256) { l += 8; x >>= 8; } - return l + log_2[x]; -} - - -static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, - lua_Integer v2) { - switch (op) { - case LUA_OPADD: return intop(+, v1, v2); - case LUA_OPSUB:return intop(-, v1, v2); - case LUA_OPMUL:return intop(*, v1, v2); - case LUA_OPMOD: return luaV_mod(L, v1, v2); - case LUA_OPIDIV: return luaV_div(L, v1, v2); - case LUA_OPBAND: return intop(&, v1, v2); - case LUA_OPBOR: return intop(|, v1, v2); - case LUA_OPBXOR: return intop(^, v1, v2); - case LUA_OPSHL: return luaV_shiftl(v1, v2); - case LUA_OPSHR: return luaV_shiftl(v1, -v2); - case LUA_OPUNM: return intop(-, 0, v1); - case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); - default: lua_assert(0); return 0; - } -} - - -static lua_Number numarith (lua_State *L, int op, lua_Number v1, - lua_Number v2) { - switch (op) { - case LUA_OPADD: return luai_numadd(L, v1, v2); - case LUA_OPSUB: return luai_numsub(L, v1, v2); - case LUA_OPMUL: return luai_nummul(L, v1, v2); - case LUA_OPDIV: return luai_numdiv(L, v1, v2); - case LUA_OPPOW: return luai_numpow(L, v1, v2); - case LUA_OPIDIV: return luai_numidiv(L, v1, v2); - case LUA_OPUNM: return luai_numunm(L, v1); - case LUA_OPMOD: { - lua_Number m; - luai_nummod(L, v1, v2, m); - return m; - } - default: lua_assert(0); return 0; - } -} - - -void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, - TValue *res) { - switch (op) { - case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: - case LUA_OPSHL: case LUA_OPSHR: - case LUA_OPBNOT: { /* operate only on integers */ - lua_Integer i1; lua_Integer i2; - if (tointeger(p1, &i1) && tointeger(p2, &i2)) { - setivalue(res, intarith(L, op, i1, i2)); - return; - } - else break; /* go to the end */ - } - case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ - lua_Number n1; lua_Number n2; - if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - default: { /* other operations */ - lua_Number n1; lua_Number n2; - if (ttisinteger(p1) && ttisinteger(p2)) { - setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); - return; - } - else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { - setfltvalue(res, numarith(L, op, n1, n2)); - return; - } - else break; /* go to the end */ - } - } - /* could not perform raw operation; try metamethod */ - lua_assert(L != NULL); /* should not fail when folding (compile time) */ - luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); -} - - -int luaO_hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else return (ltolower(c) - 'a') + 10; -} - - -static int isneg (const char **s) { - if (**s == '-') { (*s)++; return 1; } - else if (**s == '+') (*s)++; - return 0; -} - - - -/* -** {================================================================== -** Lua's implementation for 'lua_strx2number' -** =================================================================== -*/ - -#if !defined(lua_strx2number) - -/* maximum number of significant digits to read (to avoid overflows - even with single floats) */ -#define MAXSIGDIG 30 - -/* -** convert an hexadecimal numeric string to a number, following -** C99 specification for 'strtod' -*/ -static lua_Number lua_strx2number (const char *s, char **endptr) { - int dot = lua_getlocaledecpoint(); - lua_Number r = 0.0; /* result (accumulator) */ - int sigdig = 0; /* number of significant digits */ - int nosigdig = 0; /* number of non-significant digits */ - int e = 0; /* exponent correction */ - int neg; /* 1 if number is negative */ - int hasdot = 0; /* true after seen a dot */ - *endptr = cast(char *, s); /* nothing is valid yet */ - while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ - neg = isneg(&s); /* check signal */ - if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ - return 0.0; /* invalid format (no '0x') */ - for (s += 2; ; s++) { /* skip '0x' and read numeral */ - if (*s == dot) { - if (hasdot) break; /* second dot? stop loop */ - else hasdot = 1; - } - else if (lisxdigit(cast_uchar(*s))) { - if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ - nosigdig++; - else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ - r = (r * cast_num(16.0)) + luaO_hexavalue(*s); - else e++; /* too many digits; ignore, but still count for exponent */ - if (hasdot) e--; /* decimal digit? correct exponent */ - } - else break; /* neither a dot nor a digit */ - } - if (nosigdig + sigdig == 0) /* no digits? */ - return 0.0; /* invalid format */ - *endptr = cast(char *, s); /* valid up to here */ - e *= 4; /* each digit multiplies/divides value by 2^4 */ - if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; /* exponent value */ - int neg1; /* exponent signal */ - s++; /* skip 'p' */ - neg1 = isneg(&s); /* signal */ - if (!lisdigit(cast_uchar(*s))) - return 0.0; /* invalid; must have at least one digit */ - while (lisdigit(cast_uchar(*s))) /* read exponent */ - exp1 = exp1 * 10 + *(s++) - '0'; - if (neg1) exp1 = -exp1; - e += exp1; - *endptr = cast(char *, s); /* valid up to here */ - } - if (neg) r = -r; - return l_mathop(ldexp)(r, e); -} - -#endif -/* }====================================================== */ - - -/* maximum length of a numeral */ -#if !defined (L_MAXLENNUM) -#define L_MAXLENNUM 200 -#endif - -static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { - char *endptr; - *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ - : lua_str2number(s, &endptr); - if (endptr == s) return NULL; /* nothing recognized? */ - while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ - return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ -} - - -/* -** Convert string 's' to a Lua number (put in 'result'). Return NULL -** on fail or the address of the ending '\0' on success. -** 'pmode' points to (and 'mode' contains) special things in the string: -** - 'x'/'X' means an hexadecimal numeral -** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) -** - '.' just optimizes the search for the common case (nothing special) -** This function accepts both the current locale or a dot as the radix -** mark. If the convertion fails, it may mean number has a dot but -** locale accepts something else. In that case, the code copies 's' -** to a buffer (because 's' is read-only), changes the dot to the -** current locale radix mark, and tries to convert again. -*/ -static const char *l_str2d (const char *s, lua_Number *result) { - const char *endptr; - const char *pmode = strpbrk(s, ".xXnN"); - int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; - if (mode == 'n') /* reject 'inf' and 'nan' */ - return NULL; - endptr = l_str2dloc(s, result, mode); /* try to convert */ - if (endptr == NULL) { /* failed? may be a different locale */ - char buff[L_MAXLENNUM + 1]; - const char *pdot = strchr(s, '.'); - if (strlen(s) > L_MAXLENNUM || pdot == NULL) - return NULL; /* string too long or no dot; fail */ - strcpy(buff, s); /* copy string to buffer */ - buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ - endptr = l_str2dloc(buff, result, mode); /* try again */ - if (endptr != NULL) - endptr = s + (endptr - buff); /* make relative to 's' */ - } - return endptr; -} - - -#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) -#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) - -static const char *l_str2int (const char *s, lua_Integer *result) { - lua_Unsigned a = 0; - int empty = 1; - int neg; - while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ - neg = isneg(&s); - if (s[0] == '0' && - (s[1] == 'x' || s[1] == 'X')) { /* hex? */ - s += 2; /* skip '0x' */ - for (; lisxdigit(cast_uchar(*s)); s++) { - a = a * 16 + luaO_hexavalue(*s); - empty = 0; - } - } - else { /* decimal */ - for (; lisdigit(cast_uchar(*s)); s++) { - int d = *s - '0'; - if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ - return NULL; /* do not accept it (as integer) */ - a = a * 10 + d; - empty = 0; - } - } - while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ - if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ - else { - *result = l_castU2S((neg) ? 0u - a : a); - return s; - } -} - - -size_t luaO_str2num (const char *s, TValue *o) { - lua_Integer i; lua_Number n; - const char *e; - if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ - setivalue(o, i); - } - else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ - setfltvalue(o, n); - } - else - return 0; /* conversion failed */ - return (e - s) + 1; /* success; return string size */ -} - - -int luaO_utf8esc (char *buff, unsigned long x) { - int n = 1; /* number of bytes put in buffer (backwards) */ - lua_assert(x <= 0x10FFFF); - if (x < 0x80) /* ascii? */ - buff[UTF8BUFFSZ - 1] = cast(char, x); - else { /* need continuation bytes */ - unsigned int mfb = 0x3f; /* maximum that fits in first byte */ - do { /* add continuation bytes */ - buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); - x >>= 6; /* remove added bits */ - mfb >>= 1; /* now there is one less bit available in first byte */ - } while (x > mfb); /* still needs continuation byte? */ - buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ - } - return n; -} - - -/* maximum length of the conversion of a number to a string */ -#define MAXNUMBER2STR 50 - - -/* -** Convert a number object to a string -*/ -void luaO_tostring (lua_State *L, StkId obj) { - char buff[MAXNUMBER2STR]; - size_t len; - lua_assert(ttisnumber(obj)); - if (ttisinteger(obj)) - len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); - else { - len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); -#if !defined(LUA_COMPAT_FLOATSTRING) - if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ - buff[len++] = lua_getlocaledecpoint(); - buff[len++] = '0'; /* adds '.0' to result */ - } -#endif - } - setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); -} - - -static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); - luaD_inctop(L); -} - - -/* -** this function handles only '%d', '%c', '%f', '%p', and '%s' - conventional formats, plus Lua-specific '%I' and '%U' -*/ -const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 0; - for (;;) { - const char *e = strchr(fmt, '%'); - if (e == NULL) break; - pushstr(L, fmt, e - fmt); - switch (*(e+1)) { - case 's': { /* zero-terminated string */ - const char *s = va_arg(argp, char *); - if (s == NULL) s = "(null)"; - pushstr(L, s, strlen(s)); - break; - } - case 'c': { /* an 'int' as a character */ - char buff = cast(char, va_arg(argp, int)); - if (lisprint(cast_uchar(buff))) - pushstr(L, &buff, 1); - else /* non-printable character; print its code */ - luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); - break; - } - case 'd': { /* an 'int' */ - setivalue(L->top, va_arg(argp, int)); - goto top2str; - } - case 'I': { /* a 'lua_Integer' */ - setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); - goto top2str; - } - case 'f': { /* a 'lua_Number' */ - setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); - top2str: /* convert the top element to a string */ - luaD_inctop(L); - luaO_tostring(L, L->top - 1); - break; - } - case 'p': { /* a pointer */ - char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ - void *p = va_arg(argp, void *); - int l = lua_pointer2str(buff, sizeof(buff), p); - pushstr(L, buff, l); - break; - } - case 'U': { /* an 'int' as a UTF-8 sequence */ - char buff[UTF8BUFFSZ]; - int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); - pushstr(L, buff + UTF8BUFFSZ - l, l); - break; - } - case '%': { - pushstr(L, "%", 1); - break; - } - default: { - luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", - *(e + 1)); - } - } - n += 2; - fmt = e+2; - } - luaD_checkstack(L, 1); - pushstr(L, fmt, strlen(fmt)); - if (n > 0) luaV_concat(L, n + 1); - return svalue(L->top - 1); -} - - -const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - return msg; -} - - -/* number of chars of a literal string without the ending \0 */ -#define LL(x) (sizeof(x)/sizeof(char) - 1) - -#define RETS "..." -#define PRE "[string \"" -#define POS "\"]" - -#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) - -void luaO_chunkid (char *out, const char *source, size_t bufflen) { - size_t l = strlen(source); - if (*source == '=') { /* 'literal' source */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* truncate it */ - addstr(out, source + 1, bufflen - 1); - *out = '\0'; - } - } - else if (*source == '@') { /* file name */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* add '...' before rest of name */ - addstr(out, RETS, LL(RETS)); - bufflen -= LL(RETS); - memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); - } - } - else { /* string; format as [string "source"] */ - const char *nl = strchr(source, '\n'); /* find first new line (if any) */ - addstr(out, PRE, LL(PRE)); /* add prefix */ - bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ - if (l < bufflen && nl == NULL) { /* small one-line source? */ - addstr(out, source, l); /* keep it */ - } - else { - if (nl != NULL) l = nl - source; /* stop at first newline */ - if (l > bufflen) l = bufflen; - addstr(out, source, l); - addstr(out, RETS, LL(RETS)); - } - memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); - } -} - +/* +** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lctype.h" +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lvm.h" + + + +LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; + + +/* +** converts an integer to a "floating point byte", represented as +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. +*/ +int luaO_int2fb (unsigned int x) { + int e = 0; /* exponent */ + if (x < 8) return x; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ + e++; + } + return ((e+1) << 3) | (cast_int(x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); +} + + +/* +** Computes ceil(log2(x)) +*/ +int luaO_ceillog2 (unsigned int x) { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 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, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + int l = 0; + x--; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; +} + + +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { + switch (op) { + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftl(v1, -v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); + default: lua_assert(0); return 0; + } +} + + +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: { + lua_Number m; + luai_nummod(L, v1, v2, m); + return m; + } + default: lua_assert(0); return 0; + } +} + + +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + } + /* could not perform raw operation; try metamethod */ + lua_assert(L != NULL); /* should not fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); +} + + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; +} + + + +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 + +/* +** convert an hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + int dot = lua_getlocaledecpoint(); + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ + *endptr = cast(char *, s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ + } + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ + *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!lisdigit(cast_uchar(*s))) + return 0.0; /* invalid; must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + *endptr = cast(char *, s); /* valid up to here */ + } + if (neg) r = -r; + return l_mathop(ldexp)(r, e); +} + +#endif +/* }====================================================== */ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { + char *endptr; + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL +** on fail or the address of the ending '\0' on success. +** 'pmode' points to (and 'mode' contains) special things in the string: +** - 'x'/'X' means an hexadecimal numeral +** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) +** - '.' just optimizes the search for the common case (nothing special) +** This function accepts both the current locale or a dot as the radix +** mark. If the convertion fails, it may mean number has a dot but +** locale accepts something else. In that case, the code copies 's' +** to a buffer (because 's' is read-only), changes the dot to the +** current locale radix mark, and tries to convert again. +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ + return NULL; + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + const char *pdot = strchr(s, '.'); + if (strlen(s) > L_MAXLENNUM || pdot == NULL) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; +} + + +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast(char, x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ + } + return n; +} + + +/* maximum length of the conversion of a number to a string */ +#define MAXNUMBER2STR 50 + + +/* +** Convert a number object to a string +*/ +void luaO_tostring (lua_State *L, StkId obj) { + char buff[MAXNUMBER2STR]; + size_t len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); + else { + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); +#if !defined(LUA_COMPAT_FLOATSTRING) + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } +#endif + } + setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); +} + + +static void pushstr (lua_State *L, const char *str, size_t l) { + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); + luaD_inctop(L); +} + + +/* +** this function handles only '%d', '%c', '%f', '%p', and '%s' + conventional formats, plus Lua-specific '%I' and '%U' +*/ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + int n = 0; + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + pushstr(L, fmt, e - fmt); + switch (*(e+1)) { + case 's': { /* zero-terminated string */ + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s, strlen(s)); + break; + } + case 'c': { /* an 'int' as a character */ + char buff = cast(char, va_arg(argp, int)); + if (lisprint(cast_uchar(buff))) + pushstr(L, &buff, 1); + else /* non-printable character; print its code */ + luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); + break; + } + case 'd': { /* an 'int' */ + setivalue(L->top, va_arg(argp, int)); + goto top2str; + } + case 'I': { /* a 'lua_Integer' */ + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; + } + case 'f': { /* a 'lua_Number' */ + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: /* convert the top element to a string */ + luaD_inctop(L); + luaO_tostring(L, L->top - 1); + break; + } + case 'p': { /* a pointer */ + char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ + void *p = va_arg(argp, void *); + int l = lua_pointer2str(buff, sizeof(buff), p); + pushstr(L, buff, l); + break; + } + case 'U': { /* an 'int' as a UTF-8 sequence */ + char buff[UTF8BUFFSZ]; + int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); + pushstr(L, buff + UTF8BUFFSZ - l, l); + break; + } + case '%': { + pushstr(L, "%", 1); + break; + } + default: { + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); + } + } + n += 2; + fmt = e+2; + } + luaD_checkstack(L, 1); + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; + va_list argp; + va_start(argp, fmt); + msg = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + return msg; +} + + +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) + +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) + +void luaO_chunkid (char *out, const char *source, size_t bufflen) { + size_t l = strlen(source); + if (*source == '=') { /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } + } + else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l * sizeof(char)); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); + } + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ + if (l < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } + else { + if (nl != NULL) l = nl - source; /* stop at first newline */ + if (l > bufflen) l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); + } + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); + } +} + diff --git a/libs/lua/source/lopcodes.c b/libs/lua/source/lopcodes.c index 5ca3eb26..7d7d9c12 100644 --- a/libs/lua/source/lopcodes.c +++ b/libs/lua/source/lopcodes.c @@ -1,124 +1,124 @@ -/* -** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $ -** Opcodes for Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#define lopcodes_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lopcodes.h" - - -/* ORDER OP */ - -LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { - "MOVE", - "LOADK", - "LOADKX", - "LOADBOOL", - "LOADNIL", - "GETUPVAL", - "GETTABUP", - "GETTABLE", - "SETTABUP", - "SETUPVAL", - "SETTABLE", - "NEWTABLE", - "SELF", - "ADD", - "SUB", - "MUL", - "MOD", - "POW", - "DIV", - "IDIV", - "BAND", - "BOR", - "BXOR", - "SHL", - "SHR", - "UNM", - "BNOT", - "NOT", - "LEN", - "CONCAT", - "JMP", - "EQ", - "LT", - "LE", - "TEST", - "TESTSET", - "CALL", - "TAILCALL", - "RETURN", - "FORLOOP", - "FORPREP", - "TFORCALL", - "TFORLOOP", - "SETLIST", - "CLOSURE", - "VARARG", - "EXTRAARG", - NULL -}; - - -#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) - -LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { -/* T A B C mode opcode */ - opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ - ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ - ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ - ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ - ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ - ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ - ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ - ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ - ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ - ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ - ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ - ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ - ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ -}; - +/* +** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lopcodes_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lopcodes.h" + + +/* ORDER OP */ + +LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { + "MOVE", + "LOADK", + "LOADKX", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETTABUP", + "GETTABLE", + "SETTABUP", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "MOD", + "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", + "UNM", + "BNOT", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORCALL", + "TFORLOOP", + "SETLIST", + "CLOSURE", + "VARARG", + "EXTRAARG", + NULL +}; + + +#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) + +LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { +/* T A B C mode opcode */ + opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ + ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ + ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ + ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ + ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ +}; + diff --git a/libs/lua/source/loslib.c b/libs/lua/source/loslib.c index de590c6b..eae609b1 100644 --- a/libs/lua/source/loslib.c +++ b/libs/lua/source/loslib.c @@ -1,409 +1,409 @@ -/* -** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard Operating System library -** See Copyright Notice in lua.h -*/ - -#define loslib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** {================================================================== -** List of valid conversion specifiers for the 'strftime' function; -** options are grouped by length; group of length 2 start with '||'. -** =================================================================== -*/ -#if !defined(LUA_STRFTIMEOPTIONS) /* { */ - -/* options for ANSI C 89 (only 1-char options) */ -#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" - -/* options for ISO C 99 and POSIX */ -#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ - "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ - -/* options for Windows */ -#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ - "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ - -#if defined(LUA_USE_WINDOWS) -#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN -#elif defined(LUA_USE_C89) -#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 -#else /* C99 specification */ -#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 -#endif - -#endif /* } */ -/* }================================================================== */ - - -/* -** {================================================================== -** Configuration for time-related stuff -** =================================================================== -*/ - -#if !defined(l_time_t) /* { */ -/* -** type to represent time_t in Lua -*/ -#define l_timet lua_Integer -#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) - -static time_t l_checktime (lua_State *L, int arg) { - lua_Integer t = luaL_checkinteger(L, arg); - luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); - return (time_t)t; -} - -#endif /* } */ - - -#if !defined(l_gmtime) /* { */ -/* -** By default, Lua uses gmtime/localtime, except when POSIX is available, -** where it uses gmtime_r/localtime_r -*/ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_gmtime(t,r) gmtime_r(t,r) -#define l_localtime(t,r) localtime_r(t,r) - -#else /* }{ */ - -/* ISO C definitions */ -#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) -#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) - -#endif /* } */ - -#endif /* } */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Configuration for 'tmpnam': -** By default, Lua uses tmpnam except when POSIX is available, where -** it uses mkstemp. -** =================================================================== -*/ -#if !defined(lua_tmpnam) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define LUA_TMPNAMBUFSIZE 32 - -#if !defined(LUA_TMPNAMTEMPLATE) -#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" -#endif - -#define lua_tmpnam(b,e) { \ - strcpy(b, LUA_TMPNAMTEMPLATE); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } - -#else /* }{ */ - -/* ISO C definitions */ -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } - -#endif /* } */ - -#endif /* } */ -/* }================================================================== */ - - - - -static int os_execute (lua_State *L) { - const char *cmd = luaL_optstring(L, 1, NULL); - int stat = system(cmd); - if (cmd != NULL) - return luaL_execresult(L, stat); - else { - lua_pushboolean(L, stat); /* true if there is a shell */ - return 1; - } -} - - -static int os_remove (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - return luaL_fileresult(L, remove(filename) == 0, filename); -} - - -static int os_rename (lua_State *L) { - const char *fromname = luaL_checkstring(L, 1); - const char *toname = luaL_checkstring(L, 2); - return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); -} - - -static int os_tmpname (lua_State *L) { - char buff[LUA_TMPNAMBUFSIZE]; - int err; - lua_tmpnam(buff, err); - if (err) - return luaL_error(L, "unable to generate a unique filename"); - lua_pushstring(L, buff); - return 1; -} - - -static int os_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ - return 1; -} - - -static int os_clock (lua_State *L) { - lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); - return 1; -} - - -/* -** {====================================================== -** Time/Date operations -** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, -** wday=%w+1, yday=%j, isdst=? } -** ======================================================= -*/ - -static void setfield (lua_State *L, const char *key, int value) { - lua_pushinteger(L, value); - lua_setfield(L, -2, key); -} - -static void setboolfield (lua_State *L, const char *key, int value) { - if (value < 0) /* undefined? */ - return; /* does not set field */ - lua_pushboolean(L, value); - lua_setfield(L, -2, key); -} - - -/* -** Set all fields from structure 'tm' in the table on top of the stack -*/ -static void setallfields (lua_State *L, struct tm *stm) { - setfield(L, "sec", stm->tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon + 1); - setfield(L, "year", stm->tm_year + 1900); - setfield(L, "wday", stm->tm_wday + 1); - setfield(L, "yday", stm->tm_yday + 1); - setboolfield(L, "isdst", stm->tm_isdst); -} - - -static int getboolfield (lua_State *L, const char *key) { - int res; - res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - - -/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ -#if !defined(L_MAXDATEFIELD) -#define L_MAXDATEFIELD (INT_MAX / 2) -#endif - -static int getfield (lua_State *L, const char *key, int d, int delta) { - int isnum; - int t = lua_getfield(L, -1, key); /* get field and its type */ - lua_Integer res = lua_tointegerx(L, -1, &isnum); - if (!isnum) { /* field is not an integer? */ - if (t != LUA_TNIL) /* some other value? */ - return luaL_error(L, "field '%s' is not an integer", key); - else if (d < 0) /* absent field; no default? */ - return luaL_error(L, "field '%s' missing in date table", key); - res = d; - } - else { - if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) - return luaL_error(L, "field '%s' is out-of-bound", key); - res -= delta; - } - lua_pop(L, 1); - return (int)res; -} - - -static const char *checkoption (lua_State *L, const char *conv, - ptrdiff_t convlen, char *buff) { - const char *option = LUA_STRFTIMEOPTIONS; - int oplen = 1; /* length of options being checked */ - for (; *option != '\0' && oplen <= convlen; option += oplen) { - if (*option == '|') /* next block? */ - oplen++; /* will check options with next length (+1) */ - else if (memcmp(conv, option, oplen) == 0) { /* match? */ - memcpy(buff, conv, oplen); /* copy valid option to buffer */ - buff[oplen] = '\0'; - return conv + oplen; /* return next item */ - } - } - luaL_argerror(L, 1, - lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); - return conv; /* to avoid warnings */ -} - - -/* maximum size for an individual 'strftime' item */ -#define SIZETIMEFMT 250 - - -static int os_date (lua_State *L) { - size_t slen; - const char *s = luaL_optlstring(L, 1, "%c", &slen); - time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); - const char *se = s + slen; /* 's' end */ - struct tm tmr, *stm; - if (*s == '!') { /* UTC? */ - stm = l_gmtime(&t, &tmr); - s++; /* skip '!' */ - } - else - stm = l_localtime(&t, &tmr); - if (stm == NULL) /* invalid date? */ - return luaL_error(L, - "time result cannot be represented in this installation"); - if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setallfields(L, stm); - } - else { - char cc[4]; /* buffer for individual conversion specifiers */ - luaL_Buffer b; - cc[0] = '%'; - luaL_buffinit(L, &b); - while (s < se) { - if (*s != '%') /* not a conversion specifier? */ - luaL_addchar(&b, *s++); - else { - size_t reslen; - char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); - s++; /* skip '%' */ - s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ - reslen = strftime(buff, SIZETIMEFMT, cc, stm); - luaL_addsize(&b, reslen); - } - } - luaL_pushresult(&b); - } - return 1; -} - - -static int os_time (lua_State *L) { - time_t t; - if (lua_isnoneornil(L, 1)) /* called without args? */ - t = time(NULL); /* get current time */ - else { - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0, 0); - ts.tm_min = getfield(L, "min", 0, 0); - ts.tm_hour = getfield(L, "hour", 12, 0); - ts.tm_mday = getfield(L, "day", -1, 0); - ts.tm_mon = getfield(L, "month", -1, 1); - ts.tm_year = getfield(L, "year", -1, 1900); - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - setallfields(L, &ts); /* update fields with normalized values */ - } - if (t != (time_t)(l_timet)t || t == (time_t)(-1)) - return luaL_error(L, - "time result cannot be represented in this installation"); - l_pushtime(L, t); - return 1; -} - - -static int os_difftime (lua_State *L) { - time_t t1 = l_checktime(L, 1); - time_t t2 = l_checktime(L, 2); - lua_pushnumber(L, (lua_Number)difftime(t1, t2)); - return 1; -} - -/* }====================================================== */ - - -static int os_setlocale (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - const char *l = luaL_optstring(L, 1, NULL); - int op = luaL_checkoption(L, 2, "all", catnames); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; -} - - -static int os_exit (lua_State *L) { - int status; - if (lua_isboolean(L, 1)) - status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); - else - status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); - if (lua_toboolean(L, 2)) - lua_close(L); - if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ - return 0; -} - - -static const luaL_Reg syslib[] = { - {"clock", os_clock}, - {"date", os_date}, - {"difftime", os_difftime}, - {"execute", os_execute}, - {"exit", os_exit}, - {"getenv", os_getenv}, - {"remove", os_remove}, - {"rename", os_rename}, - {"setlocale", os_setlocale}, - {"time", os_time}, - {"tmpname", os_tmpname}, - {NULL, NULL} -}; - -/* }====================================================== */ - - - -LUAMOD_API int luaopen_os (lua_State *L) { - luaL_newlib(L, syslib); - return 1; -} - +/* +** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** {================================================================== +** List of valid conversion specifiers for the 'strftime' function; +** options are grouped by length; group of length 2 start with '||'. +** =================================================================== +*/ +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ + +/* options for ANSI C 89 (only 1-char options) */ +#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" + +/* options for ISO C 99 and POSIX */ +#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ + +/* options for Windows */ +#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ + +#if defined(LUA_USE_WINDOWS) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN +#elif defined(LUA_USE_C89) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 +#else /* C99 specification */ +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 +#endif + +#endif /* } */ +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for time-related stuff +** =================================================================== +*/ + +#if !defined(l_time_t) /* { */ +/* +** type to represent time_t in Lua +*/ +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) + +static time_t l_checktime (lua_State *L, int arg) { + lua_Integer t = luaL_checkinteger(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} + +#endif /* } */ + + +#if !defined(l_gmtime) /* { */ +/* +** By default, Lua uses gmtime/localtime, except when POSIX is available, +** where it uses gmtime_r/localtime_r +*/ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_gmtime(t,r) gmtime_r(t,r) +#define l_localtime(t,r) localtime_r(t,r) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#if !defined(lua_tmpnam) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define LUA_TMPNAMBUFSIZE 32 + +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" +#endif + +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + + + +static int os_execute (lua_State *L) { + const char *cmd = luaL_optstring(L, 1, NULL); + int stat = system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); + else { + lua_pushboolean(L, stat); /* true if there is a shell */ + return 1; + } +} + + +static int os_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return luaL_fileresult(L, remove(filename) == 0, filename); +} + + +static int os_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); +} + + +static int os_tmpname (lua_State *L) { + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); + lua_pushstring(L, buff); + return 1; +} + + +static int os_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + + +/* +** Set all fields from structure 'tm' in the table on top of the stack +*/ +static void setallfields (lua_State *L, struct tm *stm) { + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon + 1); + setfield(L, "year", stm->tm_year + 1900); + setfield(L, "wday", stm->tm_wday + 1); + setfield(L, "yday", stm->tm_yday + 1); + setboolfield(L, "isdst", stm->tm_isdst); +} + + +static int getboolfield (lua_State *L, const char *key) { + int res; + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ +#if !defined(L_MAXDATEFIELD) +#define L_MAXDATEFIELD (INT_MAX / 2) +#endif + +static int getfield (lua_State *L, const char *key, int d, int delta) { + int isnum; + int t = lua_getfield(L, -1, key); /* get field and its type */ + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not an integer? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); + res = d; + } + else { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } + lua_pop(L, 1); + return (int)res; +} + + +static const char *checkoption (lua_State *L, const char *conv, + ptrdiff_t convlen, char *buff) { + const char *option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* will check options with next length (+1) */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + +static int os_date (lua_State *L) { + size_t slen; + const char *s = luaL_optlstring(L, 1, "%c", &slen); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char *se = s + slen; /* 's' end */ + struct tm tmr, *stm; + if (*s == '!') { /* UTC? */ + stm = l_gmtime(&t, &tmr); + s++; /* skip '!' */ + } + else + stm = l_localtime(&t, &tmr); + if (stm == NULL) /* invalid date? */ + return luaL_error(L, + "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setallfields(L, stm); + } + else { + char cc[4]; /* buffer for individual conversion specifiers */ + luaL_Buffer b; + cc[0] = '%'; + luaL_buffinit(L, &b); + while (s < se) { + if (*s != '%') /* not a conversion specifier? */ + luaL_addchar(&b, *s++); + else { + size_t reslen; + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_year = getfield(L, "year", -1, 1900); + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ + } + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + return luaL_error(L, + "time result cannot be represented in this installation"); + l_pushtime(L, t); + return 1; +} + + +static int os_difftime (lua_State *L) { + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); + return 1; +} + +/* }====================================================== */ + + +static int os_setlocale (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = luaL_optstring(L, 1, NULL); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int os_exit (lua_State *L) { + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ + return 0; +} + + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUAMOD_API int luaopen_os (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + diff --git a/libs/lua/source/lparser.c b/libs/lua/source/lparser.c index cc54de43..9ed7b96f 100644 --- a/libs/lua/source/lparser.c +++ b/libs/lua/source/lparser.c @@ -1,1650 +1,1650 @@ -/* -** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - -#define lparser_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "llex.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" - - - -/* maximum number of local variables per function (must be smaller - than 250, due to the bytecode format) */ -#define MAXVARS 200 - - -#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) - - -/* because all strings are unified by the scanner, the parser - can use pointer equality for string equality */ -#define eqstr(a,b) ((a) == (b)) - - -/* -** nodes for block list (list of active blocks) -*/ -typedef struct BlockCnt { - struct BlockCnt *previous; /* chain */ - int firstlabel; /* index of first label in this block */ - int firstgoto; /* index of first pending goto in this block */ - lu_byte nactvar; /* # active locals outside the block */ - lu_byte upval; /* true if some variable in the block is an upvalue */ - lu_byte isloop; /* true if 'block' is a loop */ -} BlockCnt; - - - -/* -** prototypes for recursive non-terminal functions -*/ -static void statement (LexState *ls); -static void expr (LexState *ls, expdesc *v); - - -/* semantic error */ -static l_noret semerror (LexState *ls, const char *msg) { - ls->t.token = 0; /* remove "near " from final message */ - luaX_syntaxerror(ls, msg); -} - - -static l_noret error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); -} - - -static l_noret errorlimit (FuncState *fs, int limit, const char *what) { - lua_State *L = fs->ls->L; - const char *msg; - int line = fs->f->linedefined; - const char *where = (line == 0) - ? "main function" - : luaO_pushfstring(L, "function at line %d", line); - msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", - what, limit, where); - luaX_syntaxerror(fs->ls, msg); -} - - -static void checklimit (FuncState *fs, int v, int l, const char *what) { - if (v > l) errorlimit(fs, l, what); -} - - -static int testnext (LexState *ls, int c) { - if (ls->t.token == c) { - luaX_next(ls); - return 1; - } - else return 0; -} - - -static void check (LexState *ls, int c) { - if (ls->t.token != c) - error_expected(ls, c); -} - - -static void checknext (LexState *ls, int c) { - check(ls, c); - luaX_next(ls); -} - - -#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } - - - -static void check_match (LexState *ls, int what, int who, int where) { - if (!testnext(ls, what)) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "%s expected (to close %s at line %d)", - luaX_token2str(ls, what), luaX_token2str(ls, who), where)); - } - } -} - - -static TString *str_checkname (LexState *ls) { - TString *ts; - check(ls, TK_NAME); - ts = ls->t.seminfo.ts; - luaX_next(ls); - return ts; -} - - -static void init_exp (expdesc *e, expkind k, int i) { - e->f = e->t = NO_JUMP; - e->k = k; - e->u.info = i; -} - - -static void codestring (LexState *ls, expdesc *e, TString *s) { - init_exp(e, VK, luaK_stringK(ls->fs, s)); -} - - -static void checkname (LexState *ls, expdesc *e) { - codestring(ls, e, str_checkname(ls)); -} - - -static int registerlocalvar (LexState *ls, TString *varname) { - FuncState *fs = ls->fs; - Proto *f = fs->f; - int oldsize = f->sizelocvars; - luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, SHRT_MAX, "local variables"); - while (oldsize < f->sizelocvars) - f->locvars[oldsize++].varname = NULL; - f->locvars[fs->nlocvars].varname = varname; - luaC_objbarrier(ls->L, f, varname); - return fs->nlocvars++; -} - - -static void new_localvar (LexState *ls, TString *name) { - FuncState *fs = ls->fs; - Dyndata *dyd = ls->dyd; - int reg = registerlocalvar(ls, name); - checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, - MAXVARS, "local variables"); - luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, MAX_INT, "local variables"); - dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); -} - - -static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { - new_localvar(ls, luaX_newstring(ls, name, sz)); -} - -#define new_localvarliteral(ls,v) \ - new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) - - -static LocVar *getlocvar (FuncState *fs, int i) { - int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; - lua_assert(idx < fs->nlocvars); - return &fs->f->locvars[idx]; -} - - -static void adjustlocalvars (LexState *ls, int nvars) { - FuncState *fs = ls->fs; - fs->nactvar = cast_byte(fs->nactvar + nvars); - for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; - } -} - - -static void removevars (FuncState *fs, int tolevel) { - fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); - while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar)->endpc = fs->pc; -} - - -static int searchupvalue (FuncState *fs, TString *name) { - int i; - Upvaldesc *up = fs->f->upvalues; - for (i = 0; i < fs->nups; i++) { - if (eqstr(up[i].name, name)) return i; - } - return -1; /* not found */ -} - - -static int newupvalue (FuncState *fs, TString *name, expdesc *v) { - Proto *f = fs->f; - int oldsize = f->sizeupvalues; - checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, - Upvaldesc, MAXUPVAL, "upvalues"); - while (oldsize < f->sizeupvalues) - f->upvalues[oldsize++].name = NULL; - f->upvalues[fs->nups].instack = (v->k == VLOCAL); - f->upvalues[fs->nups].idx = cast_byte(v->u.info); - f->upvalues[fs->nups].name = name; - luaC_objbarrier(fs->ls->L, f, name); - return fs->nups++; -} - - -static int searchvar (FuncState *fs, TString *n) { - int i; - for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { - if (eqstr(n, getlocvar(fs, i)->varname)) - return i; - } - return -1; /* not found */ -} - - -/* - Mark block where variable at given level was defined - (to emit close instructions later). -*/ -static void markupval (FuncState *fs, int level) { - BlockCnt *bl = fs->bl; - while (bl->nactvar > level) - bl = bl->previous; - bl->upval = 1; -} - - -/* - Find variable with given name 'n'. If it is an upvalue, add this - upvalue into all intermediate functions. -*/ -static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) /* no more levels? */ - init_exp(var, VVOID, 0); /* default is global */ - else { - int v = searchvar(fs, n); /* look up locals at current level */ - if (v >= 0) { /* found? */ - init_exp(var, VLOCAL, v); /* variable is local */ - if (!base) - markupval(fs, v); /* local will be used as an upval */ - } - else { /* not found as local at current level; try upvalues */ - int idx = searchupvalue(fs, n); /* try existing upvalues */ - if (idx < 0) { /* not found? */ - singlevaraux(fs->prev, n, var, 0); /* try upper levels */ - if (var->k == VVOID) /* not found? */ - return; /* it is a global */ - /* else was LOCAL or UPVAL */ - idx = newupvalue(fs, n, var); /* will be a new upvalue */ - } - init_exp(var, VUPVAL, idx); /* new or old upvalue */ - } - } -} - - -static void singlevar (LexState *ls, expdesc *var) { - TString *varname = str_checkname(ls); - FuncState *fs = ls->fs; - singlevaraux(fs, varname, var, 1); - if (var->k == VVOID) { /* global name? */ - expdesc key; - singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ - lua_assert(var->k != VVOID); /* this one must exist */ - codestring(ls, &key, varname); /* key is variable name */ - luaK_indexed(fs, var, &key); /* env[varname] */ - } -} - - -static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { - FuncState *fs = ls->fs; - int extra = nvars - nexps; - if (hasmultret(e->k)) { - extra++; /* includes call itself */ - if (extra < 0) extra = 0; - luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ - if (extra > 1) luaK_reserveregs(fs, extra-1); - } - else { - if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ - if (extra > 0) { - int reg = fs->freereg; - luaK_reserveregs(fs, extra); - luaK_nil(fs, reg, extra); - } - } - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; /* remove extra values */ -} - - -static void enterlevel (LexState *ls) { - lua_State *L = ls->L; - ++L->nCcalls; - checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); -} - - -#define leavelevel(ls) ((ls)->L->nCcalls--) - - -static void closegoto (LexState *ls, int g, Labeldesc *label) { - int i; - FuncState *fs = ls->fs; - Labellist *gl = &ls->dyd->gt; - Labeldesc *gt = &gl->arr[g]; - lua_assert(eqstr(gt->name, label->name)); - if (gt->nactvar < label->nactvar) { - TString *vname = getlocvar(fs, gt->nactvar)->varname; - const char *msg = luaO_pushfstring(ls->L, - " at line %d jumps into the scope of local '%s'", - getstr(gt->name), gt->line, getstr(vname)); - semerror(ls, msg); - } - luaK_patchlist(fs, gt->pc, label->pc); - /* remove goto from pending list */ - for (i = g; i < gl->n - 1; i++) - gl->arr[i] = gl->arr[i + 1]; - gl->n--; -} - - -/* -** try to close a goto with existing labels; this solves backward jumps -*/ -static int findlabel (LexState *ls, int g) { - int i; - BlockCnt *bl = ls->fs->bl; - Dyndata *dyd = ls->dyd; - Labeldesc *gt = &dyd->gt.arr[g]; - /* check labels in current block for a match */ - for (i = bl->firstlabel; i < dyd->label.n; i++) { - Labeldesc *lb = &dyd->label.arr[i]; - if (eqstr(lb->name, gt->name)) { /* correct label? */ - if (gt->nactvar > lb->nactvar && - (bl->upval || dyd->label.n > bl->firstlabel)) - luaK_patchclose(ls->fs, gt->pc, lb->nactvar); - closegoto(ls, g, lb); /* close it */ - return 1; - } - } - return 0; /* label not found; cannot close goto */ -} - - -static int newlabelentry (LexState *ls, Labellist *l, TString *name, - int line, int pc) { - int n = l->n; - luaM_growvector(ls->L, l->arr, n, l->size, - Labeldesc, SHRT_MAX, "labels/gotos"); - l->arr[n].name = name; - l->arr[n].line = line; - l->arr[n].nactvar = ls->fs->nactvar; - l->arr[n].pc = pc; - l->n = n + 1; - return n; -} - - -/* -** check whether new label 'lb' matches any pending gotos in current -** block; solves forward jumps -*/ -static void findgotos (LexState *ls, Labeldesc *lb) { - Labellist *gl = &ls->dyd->gt; - int i = ls->fs->bl->firstgoto; - while (i < gl->n) { - if (eqstr(gl->arr[i].name, lb->name)) - closegoto(ls, i, lb); - else - i++; - } -} - - -/* -** export pending gotos to outer level, to check them against -** outer labels; if the block being exited has upvalues, and -** the goto exits the scope of any variable (which can be the -** upvalue), close those variables being exited. -*/ -static void movegotosout (FuncState *fs, BlockCnt *bl) { - int i = bl->firstgoto; - Labellist *gl = &fs->ls->dyd->gt; - /* correct pending gotos to current block and try to close it - with visible labels */ - while (i < gl->n) { - Labeldesc *gt = &gl->arr[i]; - if (gt->nactvar > bl->nactvar) { - if (bl->upval) - luaK_patchclose(fs, gt->pc, bl->nactvar); - gt->nactvar = bl->nactvar; - } - if (!findlabel(fs->ls, i)) - i++; /* move to next one */ - } -} - - -static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { - bl->isloop = isloop; - bl->nactvar = fs->nactvar; - bl->firstlabel = fs->ls->dyd->label.n; - bl->firstgoto = fs->ls->dyd->gt.n; - bl->upval = 0; - bl->previous = fs->bl; - fs->bl = bl; - lua_assert(fs->freereg == fs->nactvar); -} - - -/* -** create a label named 'break' to resolve break statements -*/ -static void breaklabel (LexState *ls) { - TString *n = luaS_new(ls->L, "break"); - int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); - findgotos(ls, &ls->dyd->label.arr[l]); -} - -/* -** generates an error for an undefined 'goto'; choose appropriate -** message when label name is a reserved word (which can only be 'break') -*/ -static l_noret undefgoto (LexState *ls, Labeldesc *gt) { - const char *msg = isreserved(gt->name) - ? "<%s> at line %d not inside a loop" - : "no visible label '%s' for at line %d"; - msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); - semerror(ls, msg); -} - - -static void leaveblock (FuncState *fs) { - BlockCnt *bl = fs->bl; - LexState *ls = fs->ls; - if (bl->previous && bl->upval) { - /* create a 'jump to here' to close upvalues */ - int j = luaK_jump(fs); - luaK_patchclose(fs, j, bl->nactvar); - luaK_patchtohere(fs, j); - } - if (bl->isloop) - breaklabel(ls); /* close pending breaks */ - fs->bl = bl->previous; - removevars(fs, bl->nactvar); - lua_assert(bl->nactvar == fs->nactvar); - fs->freereg = fs->nactvar; /* free registers */ - ls->dyd->label.n = bl->firstlabel; /* remove local labels */ - if (bl->previous) /* inner block? */ - movegotosout(fs, bl); /* update pending gotos to outer block */ - else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ - undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ -} - - -/* -** adds a new prototype into list of prototypes -*/ -static Proto *addprototype (LexState *ls) { - Proto *clp; - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; /* prototype of current function */ - if (fs->np >= f->sizep) { - int oldsize = f->sizep; - luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); - while (oldsize < f->sizep) - f->p[oldsize++] = NULL; - } - f->p[fs->np++] = clp = luaF_newproto(L); - luaC_objbarrier(L, f, clp); - return clp; -} - - -/* -** codes instruction to create new closure in parent function. -** The OP_CLOSURE instruction must use the last available register, -** so that, if it invokes the GC, the GC knows which registers -** are in use at that time. -*/ -static void codeclosure (LexState *ls, expdesc *v) { - FuncState *fs = ls->fs->prev; - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); - luaK_exp2nextreg(fs, v); /* fix it at the last register */ -} - - -static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { - Proto *f; - fs->prev = ls->fs; /* linked list of funcstates */ - fs->ls = ls; - ls->fs = fs; - fs->pc = 0; - fs->lasttarget = 0; - fs->jpc = NO_JUMP; - fs->freereg = 0; - fs->nk = 0; - fs->np = 0; - fs->nups = 0; - fs->nlocvars = 0; - fs->nactvar = 0; - fs->firstlocal = ls->dyd->actvar.n; - fs->bl = NULL; - f = fs->f; - f->source = ls->source; - f->maxstacksize = 2; /* registers 0/1 are always valid */ - enterblock(fs, bl, 0); -} - - -static void close_func (LexState *ls) { - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; - luaK_ret(fs, 0, 0); /* final return */ - leaveblock(fs); - luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); - f->sizecode = fs->pc; - luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); - f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); - f->sizek = fs->nk; - luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); - f->sizep = fs->np; - luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); - f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); - f->sizeupvalues = fs->nups; - lua_assert(fs->bl == NULL); - ls->fs = fs->prev; - luaC_checkGC(L); -} - - - -/*============================================================*/ -/* GRAMMAR RULES */ -/*============================================================*/ - - -/* -** check whether current token is in the follow set of a block. -** 'until' closes syntactical blocks, but do not close scope, -** so it is handled in separate. -*/ -static int block_follow (LexState *ls, int withuntil) { - switch (ls->t.token) { - case TK_ELSE: case TK_ELSEIF: - case TK_END: case TK_EOS: - return 1; - case TK_UNTIL: return withuntil; - default: return 0; - } -} - - -static void statlist (LexState *ls) { - /* statlist -> { stat [';'] } */ - while (!block_follow(ls, 1)) { - if (ls->t.token == TK_RETURN) { - statement(ls); - return; /* 'return' must be last statement */ - } - statement(ls); - } -} - - -static void fieldsel (LexState *ls, expdesc *v) { - /* fieldsel -> ['.' | ':'] NAME */ - FuncState *fs = ls->fs; - expdesc key; - luaK_exp2anyregup(fs, v); - luaX_next(ls); /* skip the dot or colon */ - checkname(ls, &key); - luaK_indexed(fs, v, &key); -} - - -static void yindex (LexState *ls, expdesc *v) { - /* index -> '[' expr ']' */ - luaX_next(ls); /* skip the '[' */ - expr(ls, v); - luaK_exp2val(ls->fs, v); - checknext(ls, ']'); -} - - -/* -** {====================================================================== -** Rules for Constructors -** ======================================================================= -*/ - - -struct ConsControl { - expdesc v; /* last list item read */ - expdesc *t; /* table descriptor */ - int nh; /* total number of 'record' elements */ - int na; /* total number of array elements */ - int tostore; /* number of array elements pending to be stored */ -}; - - -static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - FuncState *fs = ls->fs; - int reg = ls->fs->freereg; - expdesc key, val; - int rkkey; - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); - checkname(ls, &key); - } - else /* ls->t.token == '[' */ - yindex(ls, &key); - cc->nh++; - checknext(ls, '='); - rkkey = luaK_exp2RK(fs, &key); - expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); - fs->freereg = reg; /* free registers */ -} - - -static void closelistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->v.k == VVOID) return; /* there is no list item */ - luaK_exp2nextreg(fs, &cc->v); - cc->v.k = VVOID; - if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ - cc->tostore = 0; /* no more items pending */ - } -} - - -static void lastlistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->tostore == 0) return; - if (hasmultret(cc->v.k)) { - luaK_setmultret(fs, &cc->v); - luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); - cc->na--; /* do not count last expression (unknown number of elements) */ - } - else { - if (cc->v.k != VVOID) - luaK_exp2nextreg(fs, &cc->v); - luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); - } -} - - -static void listfield (LexState *ls, struct ConsControl *cc) { - /* listfield -> exp */ - expr(ls, &cc->v); - checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); - cc->na++; - cc->tostore++; -} - - -static void field (LexState *ls, struct ConsControl *cc) { - /* field -> listfield | recfield */ - switch(ls->t.token) { - case TK_NAME: { /* may be 'listfield' or 'recfield' */ - if (luaX_lookahead(ls) != '=') /* expression? */ - listfield(ls, cc); - else - recfield(ls, cc); - break; - } - case '[': { - recfield(ls, cc); - break; - } - default: { - listfield(ls, cc); - break; - } - } -} - - -static void constructor (LexState *ls, expdesc *t) { - /* constructor -> '{' [ field { sep field } [sep] ] '}' - sep -> ',' | ';' */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); - struct ConsControl cc; - cc.na = cc.nh = cc.tostore = 0; - cc.t = t; - init_exp(t, VRELOCABLE, pc); - init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ - checknext(ls, '{'); - do { - lua_assert(cc.v.k == VVOID || cc.tostore > 0); - if (ls->t.token == '}') break; - closelistfield(fs, &cc); - field(ls, &cc); - } while (testnext(ls, ',') || testnext(ls, ';')); - check_match(ls, '}', '{', line); - lastlistfield(fs, &cc); - SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ -} - -/* }====================================================================== */ - - - -static void parlist (LexState *ls) { - /* parlist -> [ param { ',' param } ] */ - FuncState *fs = ls->fs; - Proto *f = fs->f; - int nparams = 0; - f->is_vararg = 0; - if (ls->t.token != ')') { /* is 'parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls)); - nparams++; - break; - } - case TK_DOTS: { /* param -> '...' */ - luaX_next(ls); - f->is_vararg = 1; /* declared vararg */ - break; - } - default: luaX_syntaxerror(ls, " or '...' expected"); - } - } while (!f->is_vararg && testnext(ls, ',')); - } - adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - - -static void body (LexState *ls, expdesc *e, int ismethod, int line) { - /* body -> '(' parlist ')' block END */ - FuncState new_fs; - BlockCnt bl; - new_fs.f = addprototype(ls); - new_fs.f->linedefined = line; - open_func(ls, &new_fs, &bl); - checknext(ls, '('); - if (ismethod) { - new_localvarliteral(ls, "self"); /* create 'self' parameter */ - adjustlocalvars(ls, 1); - } - parlist(ls); - checknext(ls, ')'); - statlist(ls); - new_fs.f->lastlinedefined = ls->linenumber; - check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, e); - close_func(ls); -} - - -static int explist (LexState *ls, expdesc *v) { - /* explist -> expr { ',' expr } */ - int n = 1; /* at least one expression */ - expr(ls, v); - while (testnext(ls, ',')) { - luaK_exp2nextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; -} - - -static void funcargs (LexState *ls, expdesc *f, int line) { - FuncState *fs = ls->fs; - expdesc args; - int base, nparams; - switch (ls->t.token) { - case '(': { /* funcargs -> '(' [ explist ] ')' */ - luaX_next(ls); - if (ls->t.token == ')') /* arg list is empty? */ - args.k = VVOID; - else { - explist(ls, &args); - luaK_setmultret(fs, &args); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls, &args); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - codestring(ls, &args, ls->t.seminfo.ts); - luaX_next(ls); /* must use 'seminfo' before 'next' */ - break; - } - default: { - luaX_syntaxerror(ls, "function arguments expected"); - } - } - lua_assert(f->k == VNONRELOC); - base = f->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = LUA_MULTRET; /* open call */ - else { - if (args.k != VVOID) - luaK_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); - luaK_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves - (unless changed) one result */ -} - - - - -/* -** {====================================================================== -** Expression parsing -** ======================================================================= -*/ - - -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> NAME | '(' expr ')' */ - switch (ls->t.token) { - case '(': { - int line = ls->linenumber; - luaX_next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - luaK_dischargevars(ls->fs, v); - return; - } - case TK_NAME: { - singlevar(ls, v); - return; - } - default: { - luaX_syntaxerror(ls, "unexpected symbol"); - } - } -} - - -static void suffixedexp (LexState *ls, expdesc *v) { - /* suffixedexp -> - primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - primaryexp(ls, v); - for (;;) { - switch (ls->t.token) { - case '.': { /* fieldsel */ - fieldsel(ls, v); - break; - } - case '[': { /* '[' exp1 ']' */ - expdesc key; - luaK_exp2anyregup(fs, v); - yindex(ls, &key); - luaK_indexed(fs, v, &key); - break; - } - case ':': { /* ':' NAME funcargs */ - expdesc key; - luaX_next(ls); - checkname(ls, &key); - luaK_self(fs, v, &key); - funcargs(ls, v, line); - break; - } - case '(': case TK_STRING: case '{': { /* funcargs */ - luaK_exp2nextreg(fs, v); - funcargs(ls, v, line); - break; - } - default: return; - } - } -} - - -static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | suffixedexp */ - switch (ls->t.token) { - case TK_FLT: { - init_exp(v, VKFLT, 0); - v->u.nval = ls->t.seminfo.r; - break; - } - case TK_INT: { - init_exp(v, VKINT, 0); - v->u.ival = ls->t.seminfo.i; - break; - } - case TK_STRING: { - codestring(ls, v, ls->t.seminfo.ts); - break; - } - case TK_NIL: { - init_exp(v, VNIL, 0); - break; - } - case TK_TRUE: { - init_exp(v, VTRUE, 0); - break; - } - case TK_FALSE: { - init_exp(v, VFALSE, 0); - break; - } - case TK_DOTS: { /* vararg */ - FuncState *fs = ls->fs; - check_condition(ls, fs->f->is_vararg, - "cannot use '...' outside a vararg function"); - init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - return; - } - case TK_FUNCTION: { - luaX_next(ls); - body(ls, v, 0, ls->linenumber); - return; - } - default: { - suffixedexp(ls, v); - return; - } - } - luaX_next(ls); -} - - -static UnOpr getunopr (int op) { - switch (op) { - case TK_NOT: return OPR_NOT; - case '-': return OPR_MINUS; - case '~': return OPR_BNOT; - case '#': return OPR_LEN; - default: return OPR_NOUNOPR; - } -} - - -static BinOpr getbinopr (int op) { - switch (op) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MUL; - case '%': return OPR_MOD; - case '^': return OPR_POW; - case '/': return OPR_DIV; - case TK_IDIV: return OPR_IDIV; - case '&': return OPR_BAND; - case '|': return OPR_BOR; - case '~': return OPR_BXOR; - case TK_SHL: return OPR_SHL; - case TK_SHR: return OPR_SHR; - case TK_CONCAT: return OPR_CONCAT; - case TK_NE: return OPR_NE; - case TK_EQ: return OPR_EQ; - case '<': return OPR_LT; - case TK_LE: return OPR_LE; - case '>': return OPR_GT; - case TK_GE: return OPR_GE; - case TK_AND: return OPR_AND; - case TK_OR: return OPR_OR; - default: return OPR_NOBINOPR; - } -} - - -static const struct { - lu_byte left; /* left priority for each binary operator */ - lu_byte right; /* right priority */ -} priority[] = { /* ORDER OPR */ - {10, 10}, {10, 10}, /* '+' '-' */ - {11, 11}, {11, 11}, /* '*' '%' */ - {14, 13}, /* '^' (right associative) */ - {11, 11}, {11, 11}, /* '/' '//' */ - {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ - {7, 7}, {7, 7}, /* '<<' '>>' */ - {9, 8}, /* '..' (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ - {2, 2}, {1, 1} /* and, or */ -}; - -#define UNARY_PRIORITY 12 /* priority for unary operators */ - - -/* -** subexpr -> (simpleexp | unop subexpr) { binop subexpr } -** where 'binop' is any binary operator with a priority higher than 'limit' -*/ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { - BinOpr op; - UnOpr uop; - enterlevel(ls); - uop = getunopr(ls->t.token); - if (uop != OPR_NOUNOPR) { - int line = ls->linenumber; - luaX_next(ls); - subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls->fs, uop, v, line); - } - else simpleexp(ls, v); - /* expand while operators have priorities higher than 'limit' */ - op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && priority[op].left > limit) { - expdesc v2; - BinOpr nextop; - int line = ls->linenumber; - luaX_next(ls); - luaK_infix(ls->fs, op, v); - /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, priority[op].right); - luaK_posfix(ls->fs, op, v, &v2, line); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ -} - - -static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, 0); -} - -/* }==================================================================== */ - - - -/* -** {====================================================================== -** Rules for Statements -** ======================================================================= -*/ - - -static void block (LexState *ls) { - /* block -> statlist */ - FuncState *fs = ls->fs; - BlockCnt bl; - enterblock(fs, &bl, 0); - statlist(ls); - leaveblock(fs); -} - - -/* -** structure to chain all variables in the left-hand side of an -** assignment -*/ -struct LHS_assign { - struct LHS_assign *prev; - expdesc v; /* variable (global, local, upvalue, or indexed) */ -}; - - -/* -** check whether, in an assignment to an upvalue/local variable, the -** upvalue/local variable is begin used in a previous assignment to a -** table. If so, save original upvalue/local value in a safe place and -** use this safe copy in the previous assignment. -*/ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { - FuncState *fs = ls->fs; - int extra = fs->freereg; /* eventual position to save local variable */ - int conflict = 0; - for (; lh; lh = lh->prev) { /* check all previous assignments */ - if (lh->v.k == VINDEXED) { /* assigning to a table? */ - /* table is the upvalue/local being assigned now? */ - if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { - conflict = 1; - lh->v.u.ind.vt = VLOCAL; - lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ - } - /* index is the local being assigned? (index cannot be upvalue) */ - if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { - conflict = 1; - lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ - } - } - } - if (conflict) { - /* copy upvalue/local value to a temporary (in position 'extra') */ - OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, op, extra, v->u.info, 0); - luaK_reserveregs(fs, 1); - } -} - - -static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { - expdesc e; - check_condition(ls, vkisvar(lh->v.k), "syntax error"); - if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ - struct LHS_assign nv; - nv.prev = lh; - suffixedexp(ls, &nv.v); - if (nv.v.k != VINDEXED) - check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, - "C levels"); - assignment(ls, &nv, nvars+1); - } - else { /* assignment -> '=' explist */ - int nexps; - checknext(ls, '='); - nexps = explist(ls, &e); - if (nexps != nvars) - adjust_assign(ls, nvars, nexps, &e); - else { - luaK_setoneret(ls->fs, &e); /* close last expression */ - luaK_storevar(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } - init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ - luaK_storevar(ls->fs, &lh->v, &e); -} - - -static int cond (LexState *ls) { - /* cond -> exp */ - expdesc v; - expr(ls, &v); /* read condition */ - if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ - luaK_goiftrue(ls->fs, &v); - return v.f; -} - - -static void gotostat (LexState *ls, int pc) { - int line = ls->linenumber; - TString *label; - int g; - if (testnext(ls, TK_GOTO)) - label = str_checkname(ls); - else { - luaX_next(ls); /* skip break */ - label = luaS_new(ls->L, "break"); - } - g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); - findlabel(ls, g); /* close it if label already defined */ -} - - -/* check for repeated labels on the same block */ -static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { - int i; - for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (eqstr(label, ll->arr[i].name)) { - const char *msg = luaO_pushfstring(fs->ls->L, - "label '%s' already defined on line %d", - getstr(label), ll->arr[i].line); - semerror(fs->ls, msg); - } - } -} - - -/* skip no-op statements */ -static void skipnoopstat (LexState *ls) { - while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) - statement(ls); -} - - -static void labelstat (LexState *ls, TString *label, int line) { - /* label -> '::' NAME '::' */ - FuncState *fs = ls->fs; - Labellist *ll = &ls->dyd->label; - int l; /* index of new label being created */ - checkrepeated(fs, ll, label); /* check for repeated labels */ - checknext(ls, TK_DBCOLON); /* skip double colon */ - /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ - /* assume that locals are already out of scope */ - ll->arr[l].nactvar = fs->bl->nactvar; - } - findgotos(ls, &ll->arr[l]); -} - - -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - FuncState *fs = ls->fs; - int whileinit; - int condexit; - BlockCnt bl; - luaX_next(ls); /* skip WHILE */ - whileinit = luaK_getlabel(fs); - condexit = cond(ls); - enterblock(fs, &bl, 1); - checknext(ls, TK_DO); - block(ls); - luaK_jumpto(fs, whileinit); - check_match(ls, TK_END, TK_WHILE, line); - leaveblock(fs); - luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ -} - - -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL cond */ - int condexit; - FuncState *fs = ls->fs; - int repeat_init = luaK_getlabel(fs); - BlockCnt bl1, bl2; - enterblock(fs, &bl1, 1); /* loop block */ - enterblock(fs, &bl2, 0); /* scope block */ - luaX_next(ls); /* skip REPEAT */ - statlist(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - condexit = cond(ls); /* read condition (inside scope block) */ - if (bl2.upval) /* upvalues? */ - luaK_patchclose(fs, condexit, bl2.nactvar); - leaveblock(fs); /* finish scope */ - luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ - leaveblock(fs); /* finish loop */ -} - - -static int exp1 (LexState *ls) { - expdesc e; - int reg; - expr(ls, &e); - luaK_exp2nextreg(ls->fs, &e); - lua_assert(e.k == VNONRELOC); - reg = e.u.info; - return reg; -} - - -static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { - /* forbody -> DO block */ - BlockCnt bl; - FuncState *fs = ls->fs; - int prep, endfor; - adjustlocalvars(ls, 3); /* control variables */ - checknext(ls, TK_DO); - prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); - enterblock(fs, &bl, 0); /* scope for declared variables */ - adjustlocalvars(ls, nvars); - luaK_reserveregs(fs, nvars); - block(ls); - leaveblock(fs); /* end of scope for declared variables */ - luaK_patchtohere(fs, prep); - if (isnum) /* numeric for? */ - endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); - else { /* generic for */ - luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); - luaK_fixline(fs, line); - endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); - } - luaK_patchlist(fs, endfor, prep + 1); - luaK_fixline(fs, line); -} - - -static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ - FuncState *fs = ls->fs; - int base = fs->freereg; - new_localvarliteral(ls, "(for index)"); - new_localvarliteral(ls, "(for limit)"); - new_localvarliteral(ls, "(for step)"); - new_localvar(ls, varname); - checknext(ls, '='); - exp1(ls); /* initial value */ - checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); - luaK_reserveregs(fs, 1); - } - forbody(ls, base, line, 1, 1); -} - - -static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist forbody */ - FuncState *fs = ls->fs; - expdesc e; - int nvars = 4; /* gen, state, control, plus at least one declared var */ - int line; - int base = fs->freereg; - /* create control variables */ - new_localvarliteral(ls, "(for generator)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for control)"); - /* create declared variables */ - new_localvar(ls, indexname); - while (testnext(ls, ',')) { - new_localvar(ls, str_checkname(ls)); - nvars++; - } - checknext(ls, TK_IN); - line = ls->linenumber; - adjust_assign(ls, 3, explist(ls, &e), &e); - luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); -} - - -static void forstat (LexState *ls, int line) { - /* forstat -> FOR (fornum | forlist) END */ - FuncState *fs = ls->fs; - TString *varname; - BlockCnt bl; - enterblock(fs, &bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip 'for' */ - varname = str_checkname(ls); /* first variable name */ - switch (ls->t.token) { - case '=': fornum(ls, varname, line); break; - case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, "'=' or 'in' expected"); - } - check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); /* loop scope ('break' jumps to this point) */ -} - - -static void test_then_block (LexState *ls, int *escapelist) { - /* test_then_block -> [IF | ELSEIF] cond THEN block */ - BlockCnt bl; - FuncState *fs = ls->fs; - expdesc v; - int jf; /* instruction to skip 'then' code (if condition is false) */ - luaX_next(ls); /* skip IF or ELSEIF */ - expr(ls, &v); /* read condition */ - checknext(ls, TK_THEN); - if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { - luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ - enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - gotostat(ls, v.t); /* handle goto/break */ - while (testnext(ls, ';')) {} /* skip colons */ - if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ - leaveblock(fs); - return; /* and that is it */ - } - else /* must skip over 'then' part if condition is false */ - jf = luaK_jump(fs); - } - else { /* regular case (not goto/break) */ - luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ - enterblock(fs, &bl, 0); - jf = v.f; - } - statlist(ls); /* 'then' part */ - leaveblock(fs); - if (ls->t.token == TK_ELSE || - ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ - luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ - luaK_patchtohere(fs, jf); -} - - -static void ifstat (LexState *ls, int line) { - /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ - FuncState *fs = ls->fs; - int escapelist = NO_JUMP; /* exit list for finished parts */ - test_then_block(ls, &escapelist); /* IF cond THEN block */ - while (ls->t.token == TK_ELSEIF) - test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ - if (testnext(ls, TK_ELSE)) - block(ls); /* 'else' part */ - check_match(ls, TK_END, TK_IF, line); - luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ -} - - -static void localfunc (LexState *ls) { - expdesc b; - FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls)); /* new local variable */ - adjustlocalvars(ls, 1); /* enter its scope */ - body(ls, &b, 0, ls->linenumber); /* function created in next register */ - /* debug information will only see the variable after this point! */ - getlocvar(fs, b.u.info)->startpc = fs->pc; -} - - -static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ - int nvars = 0; - int nexps; - expdesc e; - do { - new_localvar(ls, str_checkname(ls)); - nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) - nexps = explist(ls, &e); - else { - e.k = VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, &e); - adjustlocalvars(ls, nvars); -} - - -static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {fieldsel} [':' NAME] */ - int ismethod = 0; - singlevar(ls, v); - while (ls->t.token == '.') - fieldsel(ls, v); - if (ls->t.token == ':') { - ismethod = 1; - fieldsel(ls, v); - } - return ismethod; -} - - -static void funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int ismethod; - expdesc v, b; - luaX_next(ls); /* skip FUNCTION */ - ismethod = funcname(ls, &v); - body(ls, &b, ismethod, line); - luaK_storevar(ls->fs, &v, &b); - luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ -} - - -static void exprstat (LexState *ls) { - /* stat -> func | assignment */ - FuncState *fs = ls->fs; - struct LHS_assign v; - suffixedexp(ls, &v.v); - if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ - v.prev = NULL; - assignment(ls, &v, 1); - } - else { /* stat -> func */ - check_condition(ls, v.v.k == VCALL, "syntax error"); - SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ - } -} - - -static void retstat (LexState *ls) { - /* stat -> RETURN [explist] [';'] */ - FuncState *fs = ls->fs; - expdesc e; - int first, nret; /* registers with returned values */ - if (block_follow(ls, 1) || ls->t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist(ls, &e); /* optional return values */ - if (hasmultret(e.k)) { - luaK_setmultret(fs, &e); - if (e.k == VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); - lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); - } - first = fs->nactvar; - nret = LUA_MULTRET; /* return all values */ - } - else { - if (nret == 1) /* only one single value? */ - first = luaK_exp2anyreg(fs, &e); - else { - luaK_exp2nextreg(fs, &e); /* values must go to the stack */ - first = fs->nactvar; /* return all active values */ - lua_assert(nret == fs->freereg - first); - } - } - } - luaK_ret(fs, first, nret); - testnext(ls, ';'); /* skip optional semicolon */ -} - - -static void statement (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ - enterlevel(ls); - switch (ls->t.token) { - case ';': { /* stat -> ';' (empty statement) */ - luaX_next(ls); /* skip ';' */ - break; - } - case TK_IF: { /* stat -> ifstat */ - ifstat(ls, line); - break; - } - case TK_WHILE: { /* stat -> whilestat */ - whilestat(ls, line); - break; - } - case TK_DO: { /* stat -> DO block END */ - luaX_next(ls); /* skip DO */ - block(ls); - check_match(ls, TK_END, TK_DO, line); - break; - } - case TK_FOR: { /* stat -> forstat */ - forstat(ls, line); - break; - } - case TK_REPEAT: { /* stat -> repeatstat */ - repeatstat(ls, line); - break; - } - case TK_FUNCTION: { /* stat -> funcstat */ - funcstat(ls, line); - break; - } - case TK_LOCAL: { /* stat -> localstat */ - luaX_next(ls); /* skip LOCAL */ - if (testnext(ls, TK_FUNCTION)) /* local function? */ - localfunc(ls); - else - localstat(ls); - break; - } - case TK_DBCOLON: { /* stat -> label */ - luaX_next(ls); /* skip double colon */ - labelstat(ls, str_checkname(ls), line); - break; - } - case TK_RETURN: { /* stat -> retstat */ - luaX_next(ls); /* skip RETURN */ - retstat(ls); - break; - } - case TK_BREAK: /* stat -> breakstat */ - case TK_GOTO: { /* stat -> 'goto' NAME */ - gotostat(ls, luaK_jump(ls->fs)); - break; - } - default: { /* stat -> func | assignment */ - exprstat(ls); - break; - } - } - lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && - ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* free registers */ - leavelevel(ls); -} - -/* }====================================================================== */ - - -/* -** compiles the main function, which is a regular vararg function with an -** upvalue named LUA_ENV -*/ -static void mainfunc (LexState *ls, FuncState *fs) { - BlockCnt bl; - expdesc v; - open_func(ls, fs, &bl); - fs->f->is_vararg = 1; /* main function is always declared vararg */ - init_exp(&v, VLOCAL, 0); /* create and... */ - newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ - luaX_next(ls); /* read first token */ - statlist(ls); /* parse main body */ - check(ls, TK_EOS); - close_func(ls); -} - - -LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { - LexState lexstate; - FuncState funcstate; - LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ - setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ - luaD_inctop(L); - lexstate.h = luaH_new(L); /* create table for scanner */ - sethvalue(L, L->top, lexstate.h); /* anchor it */ - luaD_inctop(L); - funcstate.f = cl->p = luaF_newproto(L); - funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ - lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ - lexstate.buff = buff; - lexstate.dyd = dyd; - dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; - luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); - mainfunc(&lexstate, &funcstate); - lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); - /* all scopes should be correctly finished */ - lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - L->top--; /* remove scanner's table */ - return cl; /* closure is on the stack, too */ -} - +/* +** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +#define lparser_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" + + + +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + + +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + + +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + + +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isloop; /* true if 'block' is a loop */ +} BlockCnt; + + + +/* +** prototypes for recursive non-terminal functions +*/ +static void statement (LexState *ls); +static void expr (LexState *ls, expdesc *v); + + +/* semantic error */ +static l_noret semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove "near " from final message */ + luaX_syntaxerror(ls, msg); +} + + +static l_noret error_expected (LexState *ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); +} + + +static l_noret errorlimit (FuncState *fs, int limit, const char *what) { + lua_State *L = fs->ls->L; + const char *msg; + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); +} + + +static int testnext (LexState *ls, int c) { + if (ls->t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; +} + + +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); +} + + +static void checknext (LexState *ls, int c) { + check(ls, c); + luaX_next(ls); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + + +static void check_match (LexState *ls, int what, int who, int where) { + if (!testnext(ls, what)) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "%s expected (to close %s at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } +} + + +static TString *str_checkname (LexState *ls) { + TString *ts; + check(ls, TK_NAME); + ts = ls->t.seminfo.ts; + luaX_next(ls); + return ts; +} + + +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->u.info = i; +} + + +static void codestring (LexState *ls, expdesc *e, TString *s) { + init_exp(e, VK, luaK_stringK(ls->fs, s)); +} + + +static void checkname (LexState *ls, expdesc *e) { + codestring(ls, e, str_checkname(ls)); +} + + +static int registerlocalvar (LexState *ls, TString *varname) { + FuncState *fs = ls->fs; + Proto *f = fs->f; + int oldsize = f->sizelocvars; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "local variables"); + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; + f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; +} + + +static void new_localvar (LexState *ls, TString *name) { + FuncState *fs = ls->fs; + Dyndata *dyd = ls->dyd; + int reg = registerlocalvar(ls, name); + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, MAX_INT, "local variables"); + dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); +} + + +static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { + new_localvar(ls, luaX_newstring(ls, name, sz)); +} + +#define new_localvarliteral(ls,v) \ + new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) + + +static LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; +} + + +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + fs->nactvar = cast_byte(fs->nactvar + nvars); + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; + } +} + + +static void removevars (FuncState *fs, int tolevel) { + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; +} + + +static int searchupvalue (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { + Proto *f = fs->f; + int oldsize = f->sizeupvalues; + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, MAXUPVAL, "upvalues"); + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].instack = (v->k == VLOCAL); + f->upvalues[fs->nups].idx = cast_byte(v->u.info); + f->upvalues[fs->nups].name = name; + luaC_objbarrier(fs->ls->L, f, name); + return fs->nups++; +} + + +static int searchvar (FuncState *fs, TString *n) { + int i; + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { + if (eqstr(n, getlocvar(fs, i)->varname)) + return i; + } + return -1; /* not found */ +} + + +/* + Mark block where variable at given level was defined + (to emit close instructions later). +*/ +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl->nactvar > level) + bl = bl->previous; + bl->upval = 1; +} + + +/* + Find variable with given name 'n'. If it is an upvalue, add this + upvalue into all intermediate functions. +*/ +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) /* no more levels? */ + init_exp(var, VVOID, 0); /* default is global */ + else { + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ + if (!base) + markupval(fs, v); /* local will be used as an upval */ + } + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VVOID) /* not found? */ + return; /* it is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); /* new or old upvalue */ + } + } +} + + +static void singlevar (LexState *ls, expdesc *var) { + TString *varname = str_checkname(ls); + FuncState *fs = ls->fs; + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ + lua_assert(var->k != VVOID); /* this one must exist */ + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { + FuncState *fs = ls->fs; + int extra = nvars - nexps; + if (hasmultret(e->k)) { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); + } + else { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ +} + + +static void enterlevel (LexState *ls) { + lua_State *L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + +static void closegoto (LexState *ls, int g, Labeldesc *label) { + int i; + FuncState *fs = ls->fs; + Labellist *gl = &ls->dyd->gt; + Labeldesc *gt = &gl->arr[g]; + lua_assert(eqstr(gt->name, label->name)); + if (gt->nactvar < label->nactvar) { + TString *vname = getlocvar(fs, gt->nactvar)->varname; + const char *msg = luaO_pushfstring(ls->L, + " at line %d jumps into the scope of local '%s'", + getstr(gt->name), gt->line, getstr(vname)); + semerror(ls, msg); + } + luaK_patchlist(fs, gt->pc, label->pc); + /* remove goto from pending list */ + for (i = g; i < gl->n - 1; i++) + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + + +/* +** try to close a goto with existing labels; this solves backward jumps +*/ +static int findlabel (LexState *ls, int g) { + int i; + BlockCnt *bl = ls->fs->bl; + Dyndata *dyd = ls->dyd; + Labeldesc *gt = &dyd->gt.arr[g]; + /* check labels in current block for a match */ + for (i = bl->firstlabel; i < dyd->label.n; i++) { + Labeldesc *lb = &dyd->label.arr[i]; + if (eqstr(lb->name, gt->name)) { /* correct label? */ + if (gt->nactvar > lb->nactvar && + (bl->upval || dyd->label.n > bl->firstlabel)) + luaK_patchclose(ls->fs, gt->pc, lb->nactvar); + closegoto(ls, g, lb); /* close it */ + return 1; + } + } + return 0; /* label not found; cannot close goto */ +} + + +static int newlabelentry (LexState *ls, Labellist *l, TString *name, + int line, int pc) { + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].pc = pc; + l->n = n + 1; + return n; +} + + +/* +** check whether new label 'lb' matches any pending gotos in current +** block; solves forward jumps +*/ +static void findgotos (LexState *ls, Labeldesc *lb) { + Labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + while (i < gl->n) { + if (eqstr(gl->arr[i].name, lb->name)) + closegoto(ls, i, lb); + else + i++; + } +} + + +/* +** export pending gotos to outer level, to check them against +** outer labels; if the block being exited has upvalues, and +** the goto exits the scope of any variable (which can be the +** upvalue), close those variables being exited. +*/ +static void movegotosout (FuncState *fs, BlockCnt *bl) { + int i = bl->firstgoto; + Labellist *gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block and try to close it + with visible labels */ + while (i < gl->n) { + Labeldesc *gt = &gl->arr[i]; + if (gt->nactvar > bl->nactvar) { + if (bl->upval) + luaK_patchclose(fs, gt->pc, bl->nactvar); + gt->nactvar = bl->nactvar; + } + if (!findlabel(fs->ls, i)) + i++; /* move to next one */ + } +} + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { + bl->isloop = isloop; + bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; + bl->upval = 0; + bl->previous = fs->bl; + fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); +} + + +/* +** create a label named 'break' to resolve break statements +*/ +static void breaklabel (LexState *ls) { + TString *n = luaS_new(ls->L, "break"); + int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + findgotos(ls, &ls->dyd->label.arr[l]); +} + +/* +** generates an error for an undefined 'goto'; choose appropriate +** message when label name is a reserved word (which can only be 'break') +*/ +static l_noret undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg = isreserved(gt->name) + ? "<%s> at line %d not inside a loop" + : "no visible label '%s' for at line %d"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + semerror(ls, msg); +} + + +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; + LexState *ls = fs->ls; + if (bl->previous && bl->upval) { + /* create a 'jump to here' to close upvalues */ + int j = luaK_jump(fs); + luaK_patchclose(fs, j, bl->nactvar); + luaK_patchtohere(fs, j); + } + if (bl->isloop) + breaklabel(ls); /* close pending breaks */ + fs->bl = bl->previous; + removevars(fs, bl->nactvar); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + if (bl->previous) /* inner block? */ + movegotosout(fs, bl); /* update pending gotos to outer block */ + else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ +} + + +/* +** adds a new prototype into list of prototypes +*/ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; + } + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction must use the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ +} + + +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { + Proto *f; + fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + ls->fs = fs; + fs->pc = 0; + fs->lasttarget = 0; + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->np = 0; + fs->nups = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->firstlocal = ls->dyd->actvar.n; + fs->bl = NULL; + f = fs->f; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ + enterblock(fs, bl, 0); +} + + +static void close_func (LexState *ls) { + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaK_ret(fs, 0, 0); /* final return */ + leaveblock(fs); + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; + lua_assert(fs->bl == NULL); + ls->fs = fs->prev; + luaC_checkGC(L); +} + + + +/*============================================================*/ +/* GRAMMAR RULES */ +/*============================================================*/ + + +/* +** check whether current token is in the follow set of a block. +** 'until' closes syntactical blocks, but do not close scope, +** so it is handled in separate. +*/ +static int block_follow (LexState *ls, int withuntil) { + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } +} + + +static void statlist (LexState *ls) { + /* statlist -> { stat [';'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + + +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyregup(fs, v); + luaX_next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); +} + + +static void yindex (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + luaX_next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + checknext(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of 'record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + + +static void recfield (LexState *ls, struct ConsControl *cc) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + FuncState *fs = ls->fs; + int reg = ls->fs->freereg; + expdesc key, val; + int rkkey; + if (ls->t.token == TK_NAME) { + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + yindex(ls, &key); + cc->nh++; + checknext(ls, '='); + rkkey = luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->tostore = 0; /* no more items pending */ + } +} + + +static void lastlistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->tostore == 0) return; + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); + cc->na--; /* do not count last expression (unknown number of elements) */ + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); + } +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + /* listfield -> exp */ + expr(ls, &cc->v); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + cc->na++; + cc->tostore++; +} + + +static void field (LexState *ls, struct ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ + checknext(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + field(ls, &cc); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ +} + +/* }====================================================================== */ + + + +static void parlist (LexState *ls) { + /* parlist -> [ param { ',' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; + int nparams = 0; + f->is_vararg = 0; + if (ls->t.token != ')') { /* is 'parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_NAME: { /* param -> NAME */ + new_localvar(ls, str_checkname(ls)); + nparams++; + break; + } + case TK_DOTS: { /* param -> '...' */ + luaX_next(ls); + f->is_vararg = 1; /* declared vararg */ + break; + } + default: luaX_syntaxerror(ls, " or '...' expected"); + } + } while (!f->is_vararg && testnext(ls, ',')); + } + adjustlocalvars(ls, nparams); + f->numparams = cast_byte(fs->nactvar); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ +} + + +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> '(' parlist ')' block END */ + FuncState new_fs; + BlockCnt bl; + new_fs.f = addprototype(ls); + new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); + checknext(ls, '('); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + statlist(ls); + new_fs.f->lastlinedefined = ls->linenumber; + check_match(ls, TK_END, TK_FUNCTION, line); + codeclosure(ls, e); + close_func(ls); +} + + +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); + n++; + } + return n; +} + + +static void funcargs (LexState *ls, expdesc *f, int line) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist ] ')' */ + luaX_next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist(ls, &args); + luaK_setmultret(fs, &args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); + break; + } + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + luaX_next(ls); /* must use 'seminfo' before 'next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + } + } + lua_assert(f->k == VNONRELOC); + base = f->u.info; /* base register for call */ + if (hasmultret(args.k)) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); + } + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ +} + + + + +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ + switch (ls->t.token) { + case '(': { + int line = ls->linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + } + } +} + + +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + primaryexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* fieldsel */ + fieldsel(ls, v); + break; + } + case '[': { /* '[' exp1 ']' */ + expdesc key; + luaK_exp2anyregup(fs, v); + yindex(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* ':' NAME funcargs */ + expdesc key; + luaX_next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v, line); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v, line); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | + constructor | FUNCTION body | suffixedexp */ + switch (ls->t.token) { + case TK_FLT: { + init_exp(v, VKFLT, 0); + v->u.nval = ls->t.seminfo.r; + break; + } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + break; + } + case TK_NIL: { + init_exp(v, VNIL, 0); + break; + } + case TK_TRUE: { + init_exp(v, VTRUE, 0); + break; + } + case TK_FALSE: { + init_exp(v, VFALSE, 0); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use '...' outside a vararg function"); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls->linenumber); + return; + } + default: { + suffixedexp(ls, v); + return; + } + } + luaX_next(ls); +} + + +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + case '~': return OPR_BNOT; + case '#': return OPR_LEN; + default: return OPR_NOUNOPR; + } +} + + +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MUL; + case '%': return OPR_MOD; + case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; + } +} + + +static const struct { + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ +}; + +#define UNARY_PRIORITY 12 /* priority for unary operators */ + + +/* +** subexpr -> (simpleexp | unop subexpr) { binop subexpr } +** where 'binop' is any binary operator with a priority higher than 'limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + int line = ls->linenumber; + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls->fs, uop, v, line); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than 'limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + int line = ls->linenumber; + luaX_next(ls); + luaK_infix(ls->fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls->fs, op, v, &v2, line); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ +} + + +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, 0); +} + +/* }==================================================================== */ + + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ + + +static void block (LexState *ls) { + /* block -> statlist */ + FuncState *fs = ls->fs; + BlockCnt bl; + enterblock(fs, &bl, 0); + statlist(ls); + leaveblock(fs); +} + + +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to an upvalue/local variable, the +** upvalue/local variable is begin used in a previous assignment to a +** table. If so, save original upvalue/local value in a safe place and +** use this safe copy in the previous assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (lh->v.k == VINDEXED) { /* assigning to a table? */ + /* table is the upvalue/local being assigned now? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* index is the local being assigned? (index cannot be upvalue) */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, extra, v->u.info, 0); + luaK_reserveregs(fs, 1); + } +} + + +static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, vkisvar(lh->v.k), "syntax error"); + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + suffixedexp(ls, &nv.v); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); + checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, + "C levels"); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist */ + int nexps; + checknext(ls, '='); + nexps = explist(ls, &e); + if (nexps != nvars) + adjust_assign(ls, nvars, nexps, &e); + else { + luaK_setoneret(ls->fs, &e); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } + } + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); +} + + +static int cond (LexState *ls) { + /* cond -> exp */ + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + return v.f; +} + + +static void gotostat (LexState *ls, int pc) { + int line = ls->linenumber; + TString *label; + int g; + if (testnext(ls, TK_GOTO)) + label = str_checkname(ls); + else { + luaX_next(ls); /* skip break */ + label = luaS_new(ls->L, "break"); + } + g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); + findlabel(ls, g); /* close it if label already defined */ +} + + +/* check for repeated labels on the same block */ +static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { + int i; + for (i = fs->bl->firstlabel; i < ll->n; i++) { + if (eqstr(label, ll->arr[i].name)) { + const char *msg = luaO_pushfstring(fs->ls->L, + "label '%s' already defined on line %d", + getstr(label), ll->arr[i].line); + semerror(fs->ls, msg); + } + } +} + + +/* skip no-op statements */ +static void skipnoopstat (LexState *ls) { + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); +} + + +static void labelstat (LexState *ls, TString *label, int line) { + /* label -> '::' NAME '::' */ + FuncState *fs = ls->fs; + Labellist *ll = &ls->dyd->label; + int l; /* index of new label being created */ + checkrepeated(fs, ll, label); /* check for repeated labels */ + checknext(ls, TK_DBCOLON); /* skip double colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); + skipnoopstat(ls); /* skip other no-op statements */ + if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + findgotos(ls, &ll->arr[l]); +} + + +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int whileinit; + int condexit; + BlockCnt bl; + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, &bl, 1); + checknext(ls, TK_DO); + block(ls); + luaK_jumpto(fs, whileinit); + check_match(ls, TK_END, TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ +} + + +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + int condexit; + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + statlist(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (bl2.upval) /* upvalues? */ + luaK_patchclose(fs, condexit, bl2.nactvar); + leaveblock(fs); /* finish scope */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ + leaveblock(fs); /* finish loop */ +} + + +static int exp1 (LexState *ls) { + expdesc e; + int reg; + expr(ls, &e); + luaK_exp2nextreg(ls->fs, &e); + lua_assert(e.k == VNONRELOC); + reg = e.u.info; + return reg; +} + + +static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ + BlockCnt bl; + FuncState *fs = ls->fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, TK_DO); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + if (isnum) /* numeric for? */ + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else { /* generic for */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); +} + + +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',')) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base, line, 1, 1); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME {,NAME} IN explist forbody */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 4; /* gen, state, control, plus at least one declared var */ + int line; + int base = fs->freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); + /* create declared variables */ + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } + checknext(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, 3, explist(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base, line, nvars - 3, 0); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> FOR (fornum | forlist) END */ + FuncState *fs = ls->fs; + TString *varname; + BlockCnt bl; + enterblock(fs, &bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip 'for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); + } + check_match(ls, TK_END, TK_FOR, line); + leaveblock(fs); /* loop scope ('break' jumps to this point) */ +} + + +static void test_then_block (LexState *ls, int *escapelist) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + BlockCnt bl; + FuncState *fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ + luaX_next(ls); /* skip IF or ELSEIF */ + expr(ls, &v); /* read condition */ + checknext(ls, TK_THEN); + if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { + luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + gotostat(ls, v.t); /* handle goto/break */ + while (testnext(ls, ';')) {} /* skip colons */ + if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else { /* regular case (not goto/break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* 'then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) + block(ls); /* 'else' part */ + check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ +} + + +static void localfunc (LexState *ls) { + expdesc b; + FuncState *fs = ls->fs; + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + /* debug information will only see the variable after this point! */ + getlocvar(fs, b.u.info)->startpc = fs->pc; +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ + int nvars = 0; + int nexps; + expdesc e; + do { + new_localvar(ls, str_checkname(ls)); + nvars++; + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist(ls, &e); + else { + e.k = VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, &e); + adjustlocalvars(ls, nvars); +} + + +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME {fieldsel} [':' NAME] */ + int ismethod = 0; + singlevar(ls, v); + while (ls->t.token == '.') + fieldsel(ls, v); + if (ls->t.token == ':') { + ismethod = 1; + fieldsel(ls, v); + } + return ismethod; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int ismethod; + expdesc v, b; + luaX_next(ls); /* skip FUNCTION */ + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ +} + + +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ + FuncState *fs = ls->fs; + struct LHS_assign v; + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ + v.prev = NULL; + assignment(ls, &v, 1); + } + else { /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ + } +} + + +static void retstat (LexState *ls) { + /* stat -> RETURN [explist] [';'] */ + FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ + if (block_follow(ls, 1) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist(ls, &e); /* optional return values */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else { + luaK_exp2nextreg(fs, &e); /* values must go to the stack */ + first = fs->nactvar; /* return all active values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ +} + + +static void statement (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); + switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + break; + } + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + break; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + break; + } + case TK_DO: { /* stat -> DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + break; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + break; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + break; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + break; + } + case TK_LOCAL: { /* stat -> localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); + break; + } + case TK_DBCOLON: { /* stat -> label */ + luaX_next(ls); /* skip double colon */ + labelstat(ls, str_checkname(ls), line); + break; + } + case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ + retstat(ls); + break; + } + case TK_BREAK: /* stat -> breakstat */ + case TK_GOTO: { /* stat -> 'goto' NAME */ + gotostat(ls, luaK_jump(ls->fs)); + break; + } + default: { /* stat -> func | assignment */ + exprstat(ls); + break; + } + } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + leavelevel(ls); +} + +/* }====================================================================== */ + + +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + expdesc v; + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always declared vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { + LexState lexstate; + FuncState funcstate; + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue(L, L->top, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + /* all scopes should be correctly finished */ + lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + L->top--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ +} + diff --git a/libs/lua/source/lstate.c b/libs/lua/source/lstate.c index c1a76643..53dbb59c 100644 --- a/libs/lua/source/lstate.c +++ b/libs/lua/source/lstate.c @@ -1,347 +1,347 @@ -/* -** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - -#define lstate_c -#define LUA_CORE - -#include "lprefix.h" - - -#include -#include - -#include "lua.h" - -#include "lapi.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "llex.h" -#include "lmem.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -#if !defined(LUAI_GCPAUSE) -#define LUAI_GCPAUSE 200 /* 200% */ -#endif - -#if !defined(LUAI_GCMUL) -#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ -#endif - - -/* -** a macro to help the creation of a unique random seed when a state is -** created; the seed is used to randomize hashes. -*/ -#if !defined(luai_makeseed) -#include -#define luai_makeseed() cast(unsigned int, time(NULL)) -#endif - - - -/* -** thread state + extra space -*/ -typedef struct LX { - lu_byte extra_[LUA_EXTRASPACE]; - lua_State l; -} LX; - - -/* -** Main thread combines a thread state and the global state -*/ -typedef struct LG { - LX l; - global_State g; -} LG; - - - -#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) - - -/* -** Compute an initial seed as random as possible. Rely on Address Space -** Layout Randomization (if present) to increase randomness.. -*/ -#define addbuff(b,p,e) \ - { size_t t = cast(size_t, e); \ - memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } - -static unsigned int makeseed (lua_State *L) { - char buff[4 * sizeof(size_t)]; - unsigned int h = luai_makeseed(); - int p = 0; - addbuff(buff, p, L); /* heap variable */ - addbuff(buff, p, &h); /* local variable */ - addbuff(buff, p, luaO_nilobject); /* global variable */ - addbuff(buff, p, &lua_newstate); /* public function */ - lua_assert(p == sizeof(buff)); - return luaS_hash(buff, p, h); -} - - -/* -** set GCdebt to a new value keeping the value (totalbytes + GCdebt) -** invariant (and avoiding underflows in 'totalbytes') -*/ -void luaE_setdebt (global_State *g, l_mem debt) { - l_mem tb = gettotalbytes(g); - lua_assert(tb > 0); - if (debt < tb - MAX_LMEM) - debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ - g->totalbytes = tb - debt; - g->GCdebt = debt; -} - - -CallInfo *luaE_extendCI (lua_State *L) { - CallInfo *ci = luaM_new(L, CallInfo); - lua_assert(L->ci->next == NULL); - L->ci->next = ci; - ci->previous = L->ci; - ci->next = NULL; - L->nci++; - return ci; -} - - -/* -** free all CallInfo structures not in use by a thread -*/ -void luaE_freeCI (lua_State *L) { - CallInfo *ci = L->ci; - CallInfo *next = ci->next; - ci->next = NULL; - while ((ci = next) != NULL) { - next = ci->next; - luaM_free(L, ci); - L->nci--; - } -} - - -/* -** free half of the CallInfo structures not in use by a thread -*/ -void luaE_shrinkCI (lua_State *L) { - CallInfo *ci = L->ci; - CallInfo *next2; /* next's next */ - /* while there are two nexts */ - while (ci->next != NULL && (next2 = ci->next->next) != NULL) { - luaM_free(L, ci->next); /* free next */ - L->nci--; - ci->next = next2; /* remove 'next' from the list */ - next2->previous = ci; - ci = next2; /* keep next's next */ - } -} - - -static void stack_init (lua_State *L1, lua_State *L) { - int i; CallInfo *ci; - /* initialize stack array */ - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); - L1->stacksize = BASIC_STACK_SIZE; - for (i = 0; i < BASIC_STACK_SIZE; i++) - setnilvalue(L1->stack + i); /* erase new stack */ - L1->top = L1->stack; - L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; - /* initialize first ci */ - ci = &L1->base_ci; - ci->next = ci->previous = NULL; - ci->callstatus = 0; - ci->func = L1->top; - setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ - ci->top = L1->top + LUA_MINSTACK; - L1->ci = ci; -} - - -static void freestack (lua_State *L) { - if (L->stack == NULL) - return; /* stack not completely built yet */ - L->ci = &L->base_ci; /* free the entire 'ci' list */ - luaE_freeCI(L); - lua_assert(L->nci == 0); - luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ -} - - -/* -** Create registry table and its predefined values -*/ -static void init_registry (lua_State *L, global_State *g) { - TValue temp; - /* create registry */ - Table *registry = luaH_new(L); - sethvalue(L, &g->l_registry, registry); - luaH_resize(L, registry, LUA_RIDX_LAST, 0); - /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &temp, L); /* temp = L */ - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); - /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); -} - - -/* -** open parts of the state that may cause memory-allocation errors. -** ('g->version' != NULL flags that the state was completely build) -*/ -static void f_luaopen (lua_State *L, void *ud) { - global_State *g = G(L); - UNUSED(ud); - stack_init(L, L); /* init stack */ - init_registry(L, g); - luaS_init(L); - luaT_init(L); - luaX_init(L); - g->gcrunning = 1; /* allow gc */ - g->version = lua_version(NULL); - luai_userstateopen(L); -} - - -/* -** preinitialize a thread with consistent values without allocating -** any memory (to avoid errors) -*/ -static void preinit_thread (lua_State *L, global_State *g) { - G(L) = g; - L->stack = NULL; - L->ci = NULL; - L->nci = 0; - L->stacksize = 0; - L->twups = L; /* thread has no upvalues */ - L->errorJmp = NULL; - L->nCcalls = 0; - L->hook = NULL; - L->hookmask = 0; - L->basehookcount = 0; - L->allowhook = 1; - resethookcount(L); - L->openupval = NULL; - L->nny = 1; - L->status = LUA_OK; - L->errfunc = 0; -} - - -static void close_state (lua_State *L) { - global_State *g = G(L); - luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_freeallobjects(L); /* collect all objects */ - if (g->version) /* closing a fully built state? */ - luai_userstateclose(L); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); - freestack(L); - lua_assert(gettotalbytes(g) == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ -} - - -LUA_API lua_State *lua_newthread (lua_State *L) { - global_State *g = G(L); - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - /* create new thread */ - L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; - L1->marked = luaC_white(g); - L1->tt = LUA_TTHREAD; - /* link it on list 'allgc' */ - L1->next = g->allgc; - g->allgc = obj2gco(L1); - /* anchor it on L stack */ - setthvalue(L, L->top, L1); - api_incr_top(L); - preinit_thread(L1, g); - L1->hookmask = L->hookmask; - L1->basehookcount = L->basehookcount; - L1->hook = L->hook; - resethookcount(L1); - /* initialize L1 extra space */ - memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), - LUA_EXTRASPACE); - luai_userstatethread(L, L1); - stack_init(L1, L); /* init stack */ - lua_unlock(L); - return L1; -} - - -void luaE_freethread (lua_State *L, lua_State *L1) { - LX *l = fromstate(L1); - luaF_close(L1, L1->stack); /* close all upvalues for this thread */ - lua_assert(L1->openupval == NULL); - luai_userstatefree(L, L1); - freestack(L1); - luaM_free(L, l); -} - - -LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { - int i; - lua_State *L; - global_State *g; - LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); - if (l == NULL) return NULL; - L = &l->l.l; - g = &l->g; - L->next = NULL; - L->tt = LUA_TTHREAD; - g->currentwhite = bitmask(WHITE0BIT); - L->marked = luaC_white(g); - preinit_thread(L, g); - g->frealloc = f; - g->ud = ud; - g->mainthread = L; - g->seed = makeseed(L); - g->gcrunning = 0; /* no GC while building state */ - g->GCestimate = 0; - g->strt.size = g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(&g->l_registry); - g->panic = NULL; - g->version = NULL; - g->gcstate = GCSpause; - g->gckind = KGC_NORMAL; - g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; - g->sweepgc = NULL; - g->gray = g->grayagain = NULL; - g->weak = g->ephemeron = g->allweak = NULL; - g->twups = NULL; - g->totalbytes = sizeof(LG); - g->GCdebt = 0; - g->gcfinnum = 0; - g->gcpause = LUAI_GCPAUSE; - g->gcstepmul = LUAI_GCMUL; - for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } - return L; -} - - -LUA_API void lua_close (lua_State *L) { - L = G(L)->mainthread; /* only the main thread can be closed */ - lua_lock(L); - close_state(L); -} - - +/* +** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include + +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +#if !defined(LUAI_GCPAUSE) +#define LUAI_GCPAUSE 200 /* 200% */ +#endif + +#if !defined(LUAI_GCMUL) +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ +#endif + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include +#define luai_makeseed() cast(unsigned int, time(NULL)) +#endif + + + +/* +** thread state + extra space +*/ +typedef struct LX { + lu_byte extra_[LUA_EXTRASPACE]; + lua_State l; +} LX; + + +/* +** Main thread combines a thread state and the global state +*/ +typedef struct LG { + LX l; + global_State g; +} LG; + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + +/* +** Compute an initial seed as random as possible. Rely on Address Space +** Layout Randomization (if present) to increase randomness.. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast(size_t, e); \ + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + + +/* +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant (and avoiding underflows in 'totalbytes') +*/ +void luaE_setdebt (global_State *g, l_mem debt) { + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; + g->GCdebt = debt; +} + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + L->nci++; + return ci; +} + + +/* +** free all CallInfo structures not in use by a thread +*/ +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ + } +} + + +static void stack_init (lua_State *L1, lua_State *L) { + int i; CallInfo *ci; + /* initialize stack array */ + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); + L1->stacksize = BASIC_STACK_SIZE; + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(L1->stack + i); /* erase new stack */ + L1->top = L1->stack; + L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; +} + + +static void freestack (lua_State *L) { + if (L->stack == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); + lua_assert(L->nci == 0); + luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ +} + + +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + TValue temp; + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); +} + + +/* +** open parts of the state that may cause memory-allocation errors. +** ('g->version' != NULL flags that the state was completely build) +*/ +static void f_luaopen (lua_State *L, void *ud) { + global_State *g = G(L); + UNUSED(ud); + stack_init(L, L); /* init stack */ + init_registry(L, g); + luaS_init(L); + luaT_init(L); + luaX_init(L); + g->gcrunning = 1; /* allow gc */ + g->version = lua_version(NULL); + luai_userstateopen(L); +} + + +/* +** preinitialize a thread with consistent values without allocating +** any memory (to avoid errors) +*/ +static void preinit_thread (lua_State *L, global_State *g) { + G(L) = g; + L->stack = NULL; + L->ci = NULL; + L->nci = 0; + L->stacksize = 0; + L->twups = L; /* thread has no upvalues */ + L->errorJmp = NULL; + L->nCcalls = 0; + L->hook = NULL; + L->hookmask = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->nny = 1; + L->status = LUA_OK; + L->errfunc = 0; +} + + +static void close_state (lua_State *L) { + global_State *g = G(L); + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_freeallobjects(L); /* collect all objects */ + if (g->version) /* closing a fully built state? */ + luai_userstateclose(L); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); + freestack(L); + lua_assert(gettotalbytes(g) == sizeof(LG)); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + /* create new thread */ + L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; + L1->marked = luaC_white(g); + L1->tt = LUA_TTHREAD; + /* link it on list 'allgc' */ + L1->next = g->allgc; + g->allgc = obj2gco(L1); + /* anchor it on L stack */ + setthvalue(L, L->top, L1); + api_incr_top(L); + preinit_thread(L1, g); + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); + luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luai_userstatefree(L, L1); + freestack(L1); + luaM_free(L, l); +} + + +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; + lua_State *L; + global_State *g; + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); + if (l == NULL) return NULL; + L = &l->l.l; + g = &l->g; + L->next = NULL; + L->tt = LUA_TTHREAD; + g->currentwhite = bitmask(WHITE0BIT); + L->marked = luaC_white(g); + preinit_thread(L, g); + g->frealloc = f; + g->ud = ud; + g->mainthread = L; + g->seed = makeseed(L); + g->gcrunning = 0; /* no GC while building state */ + g->GCestimate = 0; + g->strt.size = g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(&g->l_registry); + g->panic = NULL; + g->version = NULL; + g->gcstate = GCSpause; + g->gckind = KGC_NORMAL; + g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; + g->sweepgc = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; + g->totalbytes = sizeof(LG); + g->GCdebt = 0; + g->gcfinnum = 0; + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + return L; +} + + +LUA_API void lua_close (lua_State *L) { + L = G(L)->mainthread; /* only the main thread can be closed */ + lua_lock(L); + close_state(L); +} + + diff --git a/libs/lua/source/lstring.c b/libs/lua/source/lstring.c index 6257f211..b776b022 100644 --- a/libs/lua/source/lstring.c +++ b/libs/lua/source/lstring.c @@ -1,248 +1,248 @@ -/* -** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $ -** String table (keeps all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - -#define lstring_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" - - -#define MEMERRMSG "not enough memory" - - -/* -** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to -** compute its hash -*/ -#if !defined(LUAI_HASHLIMIT) -#define LUAI_HASHLIMIT 5 -#endif - - -/* -** equality for long strings -*/ -int luaS_eqlngstr (TString *a, TString *b) { - size_t len = a->u.lnglen; - lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); - return (a == b) || /* same instance or... */ - ((len == b->u.lnglen) && /* equal length and ... */ - (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ -} - - -unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { - unsigned int h = seed ^ cast(unsigned int, l); - size_t step = (l >> LUAI_HASHLIMIT) + 1; - for (; l >= step; l -= step) - h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); - return h; -} - - -unsigned int luaS_hashlongstr (TString *ts) { - lua_assert(ts->tt == LUA_TLNGSTR); - if (ts->extra == 0) { /* no hash? */ - ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); - ts->extra = 1; /* now it has its hash */ - } - return ts->hash; -} - - -/* -** resizes the string table -*/ -void luaS_resize (lua_State *L, int newsize) { - int i; - stringtable *tb = &G(L)->strt; - if (newsize > tb->size) { /* grow table if needed */ - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - for (i = tb->size; i < newsize; i++) - tb->hash[i] = NULL; - } - for (i = 0; i < tb->size; i++) { /* rehash */ - TString *p = tb->hash[i]; - tb->hash[i] = NULL; - while (p) { /* for each node in the list */ - TString *hnext = p->u.hnext; /* save next */ - unsigned int h = lmod(p->hash, newsize); /* new position */ - p->u.hnext = tb->hash[h]; /* chain it */ - tb->hash[h] = p; - p = hnext; - } - } - if (newsize < tb->size) { /* shrink table if needed */ - /* vanishing slice should be empty */ - lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - } - tb->size = newsize; -} - - -/* -** Clear API string cache. (Entries cannot be empty, so fill them with -** a non-collectable string.) -*/ -void luaS_clearcache (global_State *g) { - int i, j; - for (i = 0; i < STRCACHE_N; i++) - for (j = 0; j < STRCACHE_M; j++) { - if (iswhite(g->strcache[i][j])) /* will entry be collected? */ - g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ - } -} - - -/* -** Initialize the string table and the string cache -*/ -void luaS_init (lua_State *L) { - global_State *g = G(L); - int i, j; - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ - /* pre-create memory-error message */ - g->memerrmsg = luaS_newliteral(L, MEMERRMSG); - luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ - for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ - for (j = 0; j < STRCACHE_M; j++) - g->strcache[i][j] = g->memerrmsg; -} - - - -/* -** creates a new string object -*/ -static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { - TString *ts; - GCObject *o; - size_t totalsize; /* total size of TString object */ - totalsize = sizelstring(l); - o = luaC_newobj(L, tag, totalsize); - ts = gco2ts(o); - ts->hash = h; - ts->extra = 0; - getstr(ts)[l] = '\0'; /* ending 0 */ - return ts; -} - - -TString *luaS_createlngstrobj (lua_State *L, size_t l) { - TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); - ts->u.lnglen = l; - return ts; -} - - -void luaS_remove (lua_State *L, TString *ts) { - stringtable *tb = &G(L)->strt; - TString **p = &tb->hash[lmod(ts->hash, tb->size)]; - while (*p != ts) /* find previous element */ - p = &(*p)->u.hnext; - *p = (*p)->u.hnext; /* remove element from its list */ - tb->nuse--; -} - - -/* -** checks whether short string exists and reuses it or creates a new one -*/ -static TString *internshrstr (lua_State *L, const char *str, size_t l) { - TString *ts; - global_State *g = G(L); - unsigned int h = luaS_hash(str, l, g->seed); - TString **list = &g->strt.hash[lmod(h, g->strt.size)]; - lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ - for (ts = *list; ts != NULL; ts = ts->u.hnext) { - if (l == ts->shrlen && - (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { - /* found! */ - if (isdead(g, ts)) /* dead (but not collected yet)? */ - changewhite(ts); /* resurrect it */ - return ts; - } - } - if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { - luaS_resize(L, g->strt.size * 2); - list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ - } - ts = createstrobj(L, l, LUA_TSHRSTR, h); - memcpy(getstr(ts), str, l * sizeof(char)); - ts->shrlen = cast_byte(l); - ts->u.hnext = *list; - *list = ts; - g->strt.nuse++; - return ts; -} - - -/* -** new string (with explicit length) -*/ -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - if (l <= LUAI_MAXSHORTLEN) /* short string? */ - return internshrstr(L, str, l); - else { - TString *ts; - if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) - luaM_toobig(L); - ts = luaS_createlngstrobj(L, l); - memcpy(getstr(ts), str, l * sizeof(char)); - return ts; - } -} - - -/* -** Create or reuse a zero-terminated string, first checking in the -** cache (using the string address as a key). The cache can contain -** only zero-terminated strings, so it is safe to use 'strcmp' to -** check hits. -*/ -TString *luaS_new (lua_State *L, const char *str) { - unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ - int j; - TString **p = G(L)->strcache[i]; - for (j = 0; j < STRCACHE_M; j++) { - if (strcmp(str, getstr(p[j])) == 0) /* hit? */ - return p[j]; /* that is it */ - } - /* normal route */ - for (j = STRCACHE_M - 1; j > 0; j--) - p[j] = p[j - 1]; /* move out last element */ - /* new element is first in the list */ - p[0] = luaS_newlstr(L, str, strlen(str)); - return p[0]; -} - - -Udata *luaS_newudata (lua_State *L, size_t s) { - Udata *u; - GCObject *o; - if (s > MAX_SIZE - sizeof(Udata)) - luaM_toobig(L); - o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); - u = gco2u(o); - u->len = s; - u->metatable = NULL; - setuservalue(L, u, luaO_nilobject); - return u; -} - +/* +** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#define lstring_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" + + +#define MEMERRMSG "not enough memory" + + +/* +** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to +** compute its hash +*/ +#if !defined(LUAI_HASHLIMIT) +#define LUAI_HASHLIMIT 5 +#endif + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->u.lnglen) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ cast(unsigned int, l); + size_t step = (l >> LUAI_HASHLIMIT) + 1; + for (; l >= step; l -= step) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); + return h; +} + + +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_TLNGSTR); + if (ts->extra == 0) { /* no hash? */ + ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + +/* +** resizes the string table +*/ +void luaS_resize (lua_State *L, int newsize) { + int i; + stringtable *tb = &G(L)->strt; + if (newsize > tb->size) { /* grow table if needed */ + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; + } + for (i = 0; i < tb->size; i++) { /* rehash */ + TString *p = tb->hash[i]; + tb->hash[i] = NULL; + while (p) { /* for each node in the list */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, newsize); /* new position */ + p->u.hnext = tb->hash[h]; /* chain it */ + tb->hash[h] = p; + p = hnext; + } + } + if (newsize < tb->size) { /* shrink table if needed */ + /* vanishing slice should be empty */ + lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + } + tb->size = newsize; +} + + +/* +** Clear API string cache. (Entries cannot be empty, so fill them with +** a non-collectable string.) +*/ +void luaS_clearcache (global_State *g) { + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } +} + + +/* +** Initialize the string table and the string cache +*/ +void luaS_init (lua_State *L) { + global_State *g = G(L); + int i, j; + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { + TString *ts; + GCObject *o; + size_t totalsize; /* total size of TString object */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ + return ts; +} + + +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { + stringtable *tb = &G(L)->strt; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { + TString *ts; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + TString **list = &g->strt.hash[lmod(h, g->strt.size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && + (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ + return ts; + } + } + if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { + luaS_resize(L, g->strt.size * 2); + list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + } + ts = createstrobj(L, l, LUA_TSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + g->strt.nuse++; + return ts; +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + TString *ts; + if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; + } +} + + +/* +** Create or reuse a zero-terminated string, first checking in the +** cache (using the string address as a key). The cache can contain +** only zero-terminated strings, so it is safe to use 'strcmp' to +** check hits. +*/ +TString *luaS_new (lua_State *L, const char *str) { + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString **p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; +} + + +Udata *luaS_newudata (lua_State *L, size_t s) { + Udata *u; + GCObject *o; + if (s > MAX_SIZE - sizeof(Udata)) + luaM_toobig(L); + o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); + u = gco2u(o); + u->len = s; + u->metatable = NULL; + setuservalue(L, u, luaO_nilobject); + return u; +} + diff --git a/libs/lua/source/lstrlib.c b/libs/lua/source/lstrlib.c index b4bed7e9..ace35cb3 100644 --- a/libs/lua/source/lstrlib.c +++ b/libs/lua/source/lstrlib.c @@ -1,1584 +1,1584 @@ -/* -** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - -#define lstrlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** maximum number of captures that a pattern can do during -** pattern-matching. This limit is arbitrary, but must fit in -** an unsigned char. -*/ -#if !defined(LUA_MAXCAPTURES) -#define LUA_MAXCAPTURES 32 -#endif - - -/* macro to 'unsign' a character */ -#define uchar(c) ((unsigned char)(c)) - - -/* -** Some sizes are better limited to fit in 'int', but must also fit in -** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) -*/ -#define MAX_SIZET ((size_t)(~(size_t)0)) - -#define MAXSIZE \ - (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) - - - - -static int str_len (lua_State *L) { - size_t l; - luaL_checklstring(L, 1, &l); - lua_pushinteger(L, (lua_Integer)l); - return 1; -} - - -/* translate a relative string position: negative means back from end */ -static lua_Integer posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -static int str_sub (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); - lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (lua_Integer)l) end = l; - if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); - else lua_pushliteral(L, ""); - return 1; -} - - -static int str_reverse (lua_State *L) { - size_t l, i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i = 0; i < l; i++) - p[i] = s[l - i - 1]; - luaL_pushresultsize(&b, l); - return 1; -} - - -static int str_lower (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i=0; i MAXSIZE / n) /* may overflow? */ - return luaL_error(L, "resulting string too large"); - else { - size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; - luaL_Buffer b; - char *p = luaL_buffinitsize(L, &b, totallen); - while (n-- > 1) { /* first n-1 copies (followed by separator) */ - memcpy(p, s, l * sizeof(char)); p += l; - if (lsep > 0) { /* empty 'memcpy' is not that cheap */ - memcpy(p, sep, lsep * sizeof(char)); - p += lsep; - } - } - memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ - luaL_pushresultsize(&b, totallen); - } - return 1; -} - - -static int str_byte (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); - lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); - int n, i; - if (posi < 1) posi = 1; - if (pose > (lua_Integer)l) pose = l; - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* arithmetic overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index %%%d", l + 1); - return l; -} - - -static int capture_to_close (MatchState *ms) { - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms->L, "invalid pattern capture"); -} - - -static const char *classend (MatchState *ms, const char *p) { - switch (*p++) { - case L_ESC: { - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (ends with '%%')"); - return p+1; - } - case '[': { - if (*p == '^') p++; - do { /* look for a ']' */ - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing ']')"); - if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. '%]') */ - } while (*p != ']'); - return p+1; - } - default: { - return p; - } - } -} - - -static int match_class (int c, int cl) { - int res; - switch (tolower(cl)) { - case 'a' : res = isalpha(c); break; - case 'c' : res = iscntrl(c); break; - case 'd' : res = isdigit(c); break; - case 'g' : res = isgraph(c); break; - case 'l' : res = islower(c); break; - case 'p' : res = ispunct(c); break; - case 's' : res = isspace(c); break; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; /* deprecated option */ - default: return (cl == c); - } - return (islower(cl) ? res : !res); -} - - -static int matchbracketclass (int c, const char *p, const char *ec) { - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the '^' */ - } - while (++p < ec) { - if (*p == L_ESC) { - p++; - if (match_class(c, uchar(*p))) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; -} - - -static int singlematch (MatchState *ms, const char *s, const char *p, - const char *ep) { - if (s >= ms->src_end) - return 0; - else { - int c = uchar(*s); - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); - } - } -} - - -static const char *matchbalance (MatchState *ms, const char *s, - const char *p) { - if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); - if (*s != *p) return NULL; - else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ -} - - -static const char *max_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - ptrdiff_t i = 0; /* counts maximum expand for item */ - while (singlematch(ms, s + i, p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; -} - - -static const char *min_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (singlematch(ms, s, p, ep)) - s++; /* try with one more repetition */ - else return NULL; - } -} - - -static const char *start_capture (MatchState *ms, const char *s, - const char *p, int what) { - const char *res; - int level = ms->level; - if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); - ms->capture[level].init = s; - ms->capture[level].len = what; - ms->level = level+1; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; -} - - -static const char *end_capture (MatchState *ms, const char *s, - const char *p) { - int l = capture_to_close(ms); - const char *res; - ms->capture[l].len = s - ms->capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == NULL) /* match failed? */ - ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; -} - - -static const char *match_capture (MatchState *ms, const char *s, int l) { - size_t len; - l = check_capture(ms, l); - len = ms->capture[l].len; - if ((size_t)(ms->src_end-s) >= len && - memcmp(ms->capture[l].init, s, len) == 0) - return s+len; - else return NULL; -} - - -static const char *match (MatchState *ms, const char *s, const char *p) { - if (ms->matchdepth-- == 0) - luaL_error(ms->L, "pattern too complex"); - init: /* using goto's to optimize tail recursion */ - if (p != ms->p_end) { /* end of pattern? */ - switch (*p) { - case '(': { /* start capture */ - if (*(p + 1) == ')') /* position capture? */ - s = start_capture(ms, s, p + 2, CAP_POSITION); - else - s = start_capture(ms, s, p + 1, CAP_UNFINISHED); - break; - } - case ')': { /* end capture */ - s = end_capture(ms, s, p + 1); - break; - } - case '$': { - if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ - goto dflt; /* no; go to default */ - s = (s == ms->src_end) ? s : NULL; /* check end of string */ - break; - } - case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ - switch (*(p + 1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p + 2); - if (s != NULL) { - p += 4; goto init; /* return match(ms, s, p + 4); */ - } /* else fail (s == NULL) */ - break; - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing '[' after '%%f' in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s - 1); - if (!matchbracketclass(uchar(previous), p, ep - 1) && - matchbracketclass(uchar(*s), p, ep - 1)) { - p = ep; goto init; /* return match(ms, s, ep); */ - } - s = NULL; /* match failed */ - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p + 1))); - if (s != NULL) { - p += 2; goto init; /* return match(ms, s, p + 2) */ - } - break; - } - default: goto dflt; - } - break; - } - default: dflt: { /* pattern class plus optional suffix */ - const char *ep = classend(ms, p); /* points to optional suffix */ - /* does not match at least once? */ - if (!singlematch(ms, s, p, ep)) { - if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ - p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ - } - else /* '+' or no suffix */ - s = NULL; /* fail */ - } - else { /* matched once */ - switch (*ep) { /* handle optional suffix */ - case '?': { /* optional */ - const char *res; - if ((res = match(ms, s + 1, ep + 1)) != NULL) - s = res; - else { - p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ - } - break; - } - case '+': /* 1 or more repetitions */ - s++; /* 1 match already done */ - /* FALLTHROUGH */ - case '*': /* 0 or more repetitions */ - s = max_expand(ms, s, p, ep); - break; - case '-': /* 0 or more repetitions (minimum) */ - s = min_expand(ms, s, p, ep); - break; - default: /* no suffix */ - s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ - } - } - break; - } - } - } - ms->matchdepth++; - return s; -} - - - -static const char *lmemfind (const char *s1, size_t l1, - const char *s2, size_t l2) { - if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ - else { - const char *init; /* to search for a '*s2' inside 's1' */ - l2--; /* 1st char will be checked by 'memchr' */ - l1 = l1-l2; /* 's2' cannot be found after that */ - while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { - init++; /* 1st char is already checked */ - if (memcmp(init, s2+1, l2) == 0) - return init-1; - else { /* correct 'l1' and 's1' to try again */ - l1 -= init-s1; - s1 = init; - } - } - return NULL; /* not found */ - } -} - - -static void push_onecapture (MatchState *ms, int i, const char *s, - const char *e) { - if (i >= ms->level) { - if (i == 0) /* ms->level == 0, too */ - lua_pushlstring(ms->L, s, e - s); /* add whole match */ - else - luaL_error(ms->L, "invalid capture index %%%d", i + 1); - } - else { - ptrdiff_t l = ms->capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); - } -} - - -static int push_captures (MatchState *ms, const char *s, const char *e) { - int i; - int nlevels = (ms->level == 0 && s) ? 1 : ms->level; - luaL_checkstack(ms->L, nlevels, "too many captures"); - for (i = 0; i < nlevels; i++) - push_onecapture(ms, i, s, e); - return nlevels; /* number of strings pushed */ -} - - -/* check whether pattern has no special characters */ -static int nospecials (const char *p, size_t l) { - size_t upto = 0; - do { - if (strpbrk(p + upto, SPECIALS)) - return 0; /* pattern has a special character */ - upto += strlen(p + upto) + 1; /* may have more after \0 */ - } while (upto <= l); - return 1; /* no special chars found */ -} - - -static void prepstate (MatchState *ms, lua_State *L, - const char *s, size_t ls, const char *p, size_t lp) { - ms->L = L; - ms->matchdepth = MAXCCALLS; - ms->src_init = s; - ms->src_end = s + ls; - ms->p_end = p + lp; -} - - -static void reprepstate (MatchState *ms) { - ms->level = 0; - lua_assert(ms->matchdepth == MAXCCALLS); -} - - -static int str_find_aux (lua_State *L, int find) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); - if (init < 1) init = 1; - else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ - lua_pushnil(L); /* cannot find anything */ - return 1; - } - /* explicit request or no special characters? */ - if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { - /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); - if (s2) { - lua_pushinteger(L, (s2 - s) + 1); - lua_pushinteger(L, (s2 - s) + lp); - return 2; - } - } - else { - MatchState ms; - const char *s1 = s + init - 1; - int anchor = (*p == '^'); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, s, ls, p, lp); - do { - const char *res; - reprepstate(&ms); - if ((res=match(&ms, s1, p)) != NULL) { - if (find) { - lua_pushinteger(L, (s1 - s) + 1); /* start */ - lua_pushinteger(L, res - s); /* end */ - return push_captures(&ms, NULL, 0) + 2; - } - else - return push_captures(&ms, s1, res); - } - } while (s1++ < ms.src_end && !anchor); - } - lua_pushnil(L); /* not found */ - return 1; -} - - -static int str_find (lua_State *L) { - return str_find_aux(L, 1); -} - - -static int str_match (lua_State *L) { - return str_find_aux(L, 0); -} - - -/* state for 'gmatch' */ -typedef struct GMatchState { - const char *src; /* current position */ - const char *p; /* pattern */ - const char *lastmatch; /* end of last match */ - MatchState ms; /* match state */ -} GMatchState; - - -static int gmatch_aux (lua_State *L) { - GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); - const char *src; - gm->ms.L = L; - for (src = gm->src; src <= gm->ms.src_end; src++) { - const char *e; - reprepstate(&gm->ms); - if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { - gm->src = gm->lastmatch = e; - return push_captures(&gm->ms, src, e); - } - } - return 0; /* not found */ -} - - -static int gmatch (lua_State *L) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - GMatchState *gm; - lua_settop(L, 2); /* keep them on closure to avoid being collected */ - gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); - prepstate(&gm->ms, L, s, ls, p, lp); - gm->src = s; gm->p = p; gm->lastmatch = NULL; - lua_pushcclosure(L, gmatch_aux, 3); - return 1; -} - - -static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { - size_t l, i; - lua_State *L = ms->L; - const char *news = lua_tolstring(L, 3, &l); - for (i = 0; i < l; i++) { - if (news[i] != L_ESC) - luaL_addchar(b, news[i]); - else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) { - if (news[i] != L_ESC) - luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); - luaL_addchar(b, news[i]); - } - else if (news[i] == '0') - luaL_addlstring(b, s, e - s); - else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ - lua_remove(L, -2); /* remove original value */ - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } -} - - -static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e, int tr) { - lua_State *L = ms->L; - switch (tr) { - case LUA_TFUNCTION: { - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - break; - } - case LUA_TTABLE: { - push_onecapture(ms, 0, s, e); - lua_gettable(L, 3); - break; - } - default: { /* LUA_TNUMBER or LUA_TSTRING */ - add_s(ms, b, s, e); - return; - } - } - if (!lua_toboolean(L, -1)) { /* nil or false? */ - lua_pop(L, 1); - lua_pushlstring(L, s, e - s); /* keep original text */ - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); - luaL_addvalue(b); /* add result to accumulator */ -} - - -static int str_gsub (lua_State *L) { - size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ - const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ - const char *lastmatch = NULL; /* end of last match */ - int tr = lua_type(L, 3); /* replacement type */ - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ - int anchor = (*p == '^'); - lua_Integer n = 0; /* replacement count */ - MatchState ms; - luaL_Buffer b; - luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || - tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, - "string/function/table expected"); - luaL_buffinit(L, &b); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, src, srcl, p, lp); - while (n < max_s) { - const char *e; - reprepstate(&ms); /* (re)prepare state for new match */ - if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ - n++; - add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ - src = lastmatch = e; - } - else if (src < ms.src_end) /* otherwise, skip one character */ - luaL_addchar(&b, *src++); - else break; /* end of subject */ - if (anchor) break; - } - luaL_addlstring(&b, src, ms.src_end-src); - luaL_pushresult(&b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** STRING FORMAT -** ======================================================= -*/ - -#if !defined(lua_number2strx) /* { */ - -/* -** Hexadecimal floating-point formatter -*/ - -#include - -#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) - - -/* -** Number of bits that goes into the first digit. It can be any value -** between 1 and 4; the following definition tries to align the number -** to nibble boundaries by making what is left after that first digit a -** multiple of 4. -*/ -#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) - - -/* -** Add integer part of 'x' to buffer and return new 'x' -*/ -static lua_Number adddigit (char *buff, int n, lua_Number x) { - lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ - int d = (int)dd; - buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ - return x - dd; /* return what is left */ -} - - -static int num2straux (char *buff, int sz, lua_Number x) { - /* if 'inf' or 'NaN', format it like '%g' */ - if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) - return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); - else if (x == 0) { /* can be -0... */ - /* create "0" or "-0" followed by exponent */ - return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); - } - else { - int e; - lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ - int n = 0; /* character count */ - if (m < 0) { /* is number negative? */ - buff[n++] = '-'; /* add signal */ - m = -m; /* make it positive */ - } - buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ - m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ - e -= L_NBFD; /* this digit goes before the radix point */ - if (m > 0) { /* more digits? */ - buff[n++] = lua_getlocaledecpoint(); /* add radix point */ - do { /* add as many digits as needed */ - m = adddigit(buff, n++, m * 16); - } while (m > 0); - } - n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ - lua_assert(n < sz); - return n; - } -} - - -static int lua_number2strx (lua_State *L, char *buff, int sz, - const char *fmt, lua_Number x) { - int n = num2straux(buff, sz, x); - if (fmt[SIZELENMOD] == 'A') { - int i; - for (i = 0; i < n; i++) - buff[i] = toupper(uchar(buff[i])); - } - else if (fmt[SIZELENMOD] != 'a') - return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); - return n; -} - -#endif /* } */ - - -/* -** Maximum size of each formatted item. This maximum size is produced -** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', -** and '\0') + number of decimal digits to represent maxfloat (which -** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra -** expenses", such as locale-dependent stuff) -*/ -#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) - - -/* valid flags in a format specification */ -#define FLAGS "-+ #0" - -/* -** maximum size of each format specification (such as "%-099.99d") -*/ -#define MAX_FORMAT 32 - - -static void addquoted (luaL_Buffer *b, const char *s, size_t len) { - luaL_addchar(b, '"'); - while (len--) { - if (*s == '"' || *s == '\\' || *s == '\n') { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - } - else if (iscntrl(uchar(*s))) { - char buff[10]; - if (!isdigit(uchar(*(s+1)))) - l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); - else - l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); - luaL_addstring(b, buff); - } - else - luaL_addchar(b, *s); - s++; - } - luaL_addchar(b, '"'); -} - - -/* -** Ensures the 'buff' string uses a dot as the radix character. -*/ -static void checkdp (char *buff, int nb) { - if (memchr(buff, '.', nb) == NULL) { /* no dot? */ - char point = lua_getlocaledecpoint(); /* try locale point */ - char *ppoint = (char *)memchr(buff, point, nb); - if (ppoint) *ppoint = '.'; /* change it to a dot */ - } -} - - -static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { - switch (lua_type(L, arg)) { - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(L, arg, &len); - addquoted(b, s, len); - break; - } - case LUA_TNUMBER: { - char *buff = luaL_prepbuffsize(b, MAX_ITEM); - int nb; - if (!lua_isinteger(L, arg)) { /* float? */ - lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ - nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); - checkdp(buff, nb); /* ensure it uses a dot */ - } - else { /* integers */ - lua_Integer n = lua_tointeger(L, arg); - const char *format = (n == LUA_MININTEGER) /* corner case? */ - ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ - : LUA_INTEGER_FMT; /* else use default format */ - nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); - } - luaL_addsize(b, nb); - break; - } - case LUA_TNIL: case LUA_TBOOLEAN: { - luaL_tolstring(L, arg, NULL); - luaL_addvalue(b); - break; - } - default: { - luaL_argerror(L, arg, "value has no literal form"); - } - } -} - - -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); - *(form++) = '%'; - memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); - form += (p - strfrmt) + 1; - *form = '\0'; - return p; -} - - -/* -** add length modifier into formats -*/ -static void addlenmod (char *form, const char *lenmod) { - size_t l = strlen(form); - size_t lm = strlen(lenmod); - char spec = form[l - 1]; - strcpy(form + l - 1, lenmod); - form[l + lm - 1] = spec; - form[l + lm] = '\0'; -} - - -static int str_format (lua_State *L) { - int top = lua_gettop(L); - int arg = 1; - size_t sfl; - const char *strfrmt = luaL_checklstring(L, arg, &sfl); - const char *strfrmt_end = strfrmt+sfl; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (strfrmt < strfrmt_end) { - if (*strfrmt != L_ESC) - luaL_addchar(&b, *strfrmt++); - else if (*++strfrmt == L_ESC) - luaL_addchar(&b, *strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ - int nb = 0; /* number of bytes in added item */ - if (++arg > top) - luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); - switch (*strfrmt++) { - case 'c': { - nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); - break; - } - case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { - lua_Integer n = luaL_checkinteger(L, arg); - addlenmod(form, LUA_INTEGER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); - break; - } - case 'a': case 'A': - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = lua_number2strx(L, buff, MAX_ITEM, form, - luaL_checknumber(L, arg)); - break; - case 'e': case 'E': case 'f': - case 'g': case 'G': { - lua_Number n = luaL_checknumber(L, arg); - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); - break; - } - case 'q': { - addliteral(L, &b, arg); - break; - } - case 's': { - size_t l; - const char *s = luaL_tolstring(L, arg, &l); - if (form[2] == '\0') /* no modifiers? */ - luaL_addvalue(&b); /* keep entire string */ - else { - luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted */ - luaL_addvalue(&b); /* keep entire string */ - } - else { /* format the string into 'buff' */ - nb = l_sprintf(buff, MAX_ITEM, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - } - } - break; - } - default: { /* also treat cases 'pnLlh' */ - return luaL_error(L, "invalid option '%%%c' to 'format'", - *(strfrmt - 1)); - } - } - lua_assert(nb < MAX_ITEM); - luaL_addsize(&b, nb); - } - } - luaL_pushresult(&b); - return 1; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** PACK/UNPACK -** ======================================================= -*/ - - -/* value used for padding */ -#if !defined(LUAL_PACKPADBYTE) -#define LUAL_PACKPADBYTE 0x00 -#endif - -/* maximum size for the binary representation of an integer */ -#define MAXINTSIZE 16 - -/* number of bits in a character */ -#define NB CHAR_BIT - -/* mask for one character (NB 1's) */ -#define MC ((1 << NB) - 1) - -/* size of a lua_Integer */ -#define SZINT ((int)sizeof(lua_Integer)) - - -/* dummy union to get native endianness */ -static const union { - int dummy; - char little; /* true iff machine is little endian */ -} nativeendian = {1}; - - -/* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { double d; void *p; lua_Integer i; lua_Number n; } u; -}; - -#define MAXALIGN (offsetof(struct cD, u)) - - -/* -** Union for serializing floats -*/ -typedef union Ftypes { - float f; - double d; - lua_Number n; - char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ -} Ftypes; - - -/* -** information to pack/unpack stuff -*/ -typedef struct Header { - lua_State *L; - int islittle; - int maxalign; -} Header; - - -/* -** options for pack/unpack -*/ -typedef enum KOption { - Kint, /* signed integers */ - Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ - Kchar, /* fixed-length strings */ - Kstring, /* strings with prefixed length */ - Kzstr, /* zero-terminated strings */ - Kpadding, /* padding */ - Kpaddalign, /* padding for alignment */ - Knop /* no-op (configuration or spaces) */ -} KOption; - - -/* -** Read an integer numeral from string 'fmt' or return 'df' if -** there is no numeral -*/ -static int digit (int c) { return '0' <= c && c <= '9'; } - -static int getnum (const char **fmt, int df) { - if (!digit(**fmt)) /* no number? */ - return df; /* return default value */ - else { - int a = 0; - do { - a = a*10 + (*((*fmt)++) - '0'); - } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); - return a; - } -} - - -/* -** Read an integer numeral and raises an error if it is larger -** than the maximum size for integers. -*/ -static int getnumlimit (Header *h, const char **fmt, int df) { - int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) - return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", - sz, MAXINTSIZE); - return sz; -} - - -/* -** Initialize Header -*/ -static void initheader (lua_State *L, Header *h) { - h->L = L; - h->islittle = nativeendian.little; - h->maxalign = 1; -} - - -/* -** Read and classify next option. 'size' is filled with option's size. -*/ -static KOption getoption (Header *h, const char **fmt, int *size) { - int opt = *((*fmt)++); - *size = 0; /* default */ - switch (opt) { - case 'b': *size = sizeof(char); return Kint; - case 'B': *size = sizeof(char); return Kuint; - case 'h': *size = sizeof(short); return Kint; - case 'H': *size = sizeof(short); return Kuint; - case 'l': *size = sizeof(long); return Kint; - case 'L': *size = sizeof(long); return Kuint; - case 'j': *size = sizeof(lua_Integer); return Kint; - case 'J': *size = sizeof(lua_Integer); return Kuint; - case 'T': *size = sizeof(size_t); return Kuint; - case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; - case 'n': *size = sizeof(lua_Number); return Kfloat; - case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; - case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; - case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; - case 'c': - *size = getnum(fmt, -1); - if (*size == -1) - luaL_error(h->L, "missing size for format option 'c'"); - return Kchar; - case 'z': return Kzstr; - case 'x': *size = 1; return Kpadding; - case 'X': return Kpaddalign; - case ' ': break; - case '<': h->islittle = 1; break; - case '>': h->islittle = 0; break; - case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; - default: luaL_error(h->L, "invalid format option '%c'", opt); - } - return Knop; -} - - -/* -** Read, classify, and fill other details about the next option. -** 'psize' is filled with option's size, 'notoalign' with its -** alignment requirements. -** Local variable 'size' gets the size to be aligned. (Kpadal option -** always gets its full alignment, other options are limited by -** the maximum alignment ('maxalign'). Kchar option needs no alignment -** despite its size. -*/ -static KOption getdetails (Header *h, size_t totalsize, - const char **fmt, int *psize, int *ntoalign) { - KOption opt = getoption(h, fmt, psize); - int align = *psize; /* usually, alignment follows size */ - if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ - if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) - luaL_argerror(h->L, 1, "invalid next option for option 'X'"); - } - if (align <= 1 || opt == Kchar) /* need no alignment? */ - *ntoalign = 0; - else { - if (align > h->maxalign) /* enforce maximum alignment */ - align = h->maxalign; - if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ - luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); - *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); - } - return opt; -} - - -/* -** Pack integer 'n' with 'size' bytes and 'islittle' endianness. -** The final 'if' handles the case when 'size' is larger than -** the size of a Lua integer, correcting the extra sign-extension -** bytes if necessary (by default they would be zeros). -*/ -static void packint (luaL_Buffer *b, lua_Unsigned n, - int islittle, int size, int neg) { - char *buff = luaL_prepbuffsize(b, size); - int i; - buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ - for (i = 1; i < size; i++) { - n >>= NB; - buff[islittle ? i : size - 1 - i] = (char)(n & MC); - } - if (neg && size > SZINT) { /* negative number need sign extension? */ - for (i = SZINT; i < size; i++) /* correct extra bytes */ - buff[islittle ? i : size - 1 - i] = (char)MC; - } - luaL_addsize(b, size); /* add result to buffer */ -} - - -/* -** Copy 'size' bytes from 'src' to 'dest', correcting endianness if -** given 'islittle' is different from native endianness. -*/ -static void copywithendian (volatile char *dest, volatile const char *src, - int size, int islittle) { - if (islittle == nativeendian.little) { - while (size-- != 0) - *(dest++) = *(src++); - } - else { - dest += size - 1; - while (size-- != 0) - *(dest--) = *(src++); - } -} - - -static int str_pack (lua_State *L) { - luaL_Buffer b; - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - int arg = 1; /* current argument to pack */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - lua_pushnil(L); /* mark to separate arguments from string buffer */ - luaL_buffinit(L, &b); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - totalsize += ntoalign + size; - while (ntoalign-- > 0) - luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ - arg++; - switch (opt) { - case Kint: { /* signed integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) { /* need overflow check? */ - lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); - luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); - } - packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); - break; - } - case Kuint: { /* unsigned integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) /* need overflow check? */ - luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), - arg, "unsigned overflow"); - packint(&b, (lua_Unsigned)n, h.islittle, size, 0); - break; - } - case Kfloat: { /* floating-point options */ - volatile Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, u.buff, size, h.islittle); - luaL_addsize(&b, size); - break; - } - case Kchar: { /* fixed-size string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, len <= (size_t)size, arg, - "string longer than given size"); - luaL_addlstring(&b, s, len); /* add string */ - while (len++ < (size_t)size) /* pad extra space */ - luaL_addchar(&b, LUAL_PACKPADBYTE); - break; - } - case Kstring: { /* strings with length count */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, size >= (int)sizeof(size_t) || - len < ((size_t)1 << (size * NB)), - arg, "string length does not fit in given size"); - packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ - luaL_addlstring(&b, s, len); - totalsize += len; - break; - } - case Kzstr: { /* zero-terminated string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); - luaL_addlstring(&b, s, len); - luaL_addchar(&b, '\0'); /* add zero at the end */ - totalsize += len + 1; - break; - } - case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ - case Kpaddalign: case Knop: - arg--; /* undo increment */ - break; - } - } - luaL_pushresult(&b); - return 1; -} - - -static int str_packsize (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - size += ntoalign; /* total space used by option */ - luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, - "format result too large"); - totalsize += size; - switch (opt) { - case Kstring: /* strings with length count */ - case Kzstr: /* zero-terminated string */ - luaL_argerror(L, 1, "variable-length format"); - /* call never return, but to avoid warnings: *//* FALLTHROUGH */ - default: break; - } - } - lua_pushinteger(L, (lua_Integer)totalsize); - return 1; -} - - -/* -** Unpack an integer with 'size' bytes and 'islittle' endianness. -** If size is smaller than the size of a Lua integer and integer -** is signed, must do sign extension (propagating the sign to the -** higher bits); if size is larger than the size of a Lua integer, -** it must check the unread bytes to see whether they do not cause an -** overflow. -*/ -static lua_Integer unpackint (lua_State *L, const char *str, - int islittle, int size, int issigned) { - lua_Unsigned res = 0; - int i; - int limit = (size <= SZINT) ? size : SZINT; - for (i = limit - 1; i >= 0; i--) { - res <<= NB; - res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; - } - if (size < SZINT) { /* real size smaller than lua_Integer? */ - if (issigned) { /* needs sign extension? */ - lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); - res = ((res ^ mask) - mask); /* do sign extension */ - } - } - else if (size > SZINT) { /* must check unread bytes */ - int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; - for (i = limit; i < size; i++) { - if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) - luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); - } - } - return (lua_Integer)res; -} - - -static int str_unpack (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); - size_t ld; - const char *data = luaL_checklstring(L, 2, &ld); - size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; - int n = 0; /* number of results */ - luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); - if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) - luaL_argerror(L, 2, "data string too short"); - pos += ntoalign; /* skip alignment */ - /* stack space for item + next position */ - luaL_checkstack(L, 2, "too many results"); - n++; - switch (opt) { - case Kint: - case Kuint: { - lua_Integer res = unpackint(L, data + pos, h.islittle, size, - (opt == Kint)); - lua_pushinteger(L, res); - break; - } - case Kfloat: { - volatile Ftypes u; - lua_Number num; - copywithendian(u.buff, data + pos, size, h.islittle); - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; - lua_pushnumber(L, num); - break; - } - case Kchar: { - lua_pushlstring(L, data + pos, size); - break; - } - case Kstring: { - size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); - luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); - lua_pushlstring(L, data + pos + size, len); - pos += len; /* skip string */ - break; - } - case Kzstr: { - size_t len = (int)strlen(data + pos); - lua_pushlstring(L, data + pos, len); - pos += len + 1; /* skip string plus final '\0' */ - break; - } - case Kpaddalign: case Kpadding: case Knop: - n--; /* undo increment */ - break; - } - pos += size; - } - lua_pushinteger(L, pos + 1); /* next position */ - return n + 1; -} - -/* }====================================================== */ - - -static const luaL_Reg strlib[] = { - {"byte", str_byte}, - {"char", str_char}, - {"dump", str_dump}, - {"find", str_find}, - {"format", str_format}, - {"gmatch", gmatch}, - {"gsub", str_gsub}, - {"len", str_len}, - {"lower", str_lower}, - {"match", str_match}, - {"rep", str_rep}, - {"reverse", str_reverse}, - {"sub", str_sub}, - {"upper", str_upper}, - {"pack", str_pack}, - {"packsize", str_packsize}, - {"unpack", str_unpack}, - {NULL, NULL} -}; - - -static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* table to be metatable for strings */ - lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); /* copy table */ - lua_setmetatable(L, -2); /* set table as metatable for strings */ - lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* get string library */ - lua_setfield(L, -2, "__index"); /* metatable.__index = string */ - lua_pop(L, 1); /* pop metatable */ -} - - -/* -** Open string library -*/ -LUAMOD_API int luaopen_string (lua_State *L) { - luaL_newlib(L, strlib); - createmetatable(L); - return 1; -} - +/* +** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* translate a relative string position: negative means back from end */ +static lua_Integer posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (lua_Integer)l) end = l; + if (start <= end) + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); + lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi < 1) posi = 1; + if (pose > (lua_Integer)l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto's to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + +static int str_find_aux (lua_State *L, int find) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); + if (init < 1) init = 1; + else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); + if (s2) { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else { + MatchState ms; + const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do { + const char *res; + reprepstate(&ms); + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + +static int gmatch_aux (lua_State *L) { + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); + const char *src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { + const char *e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + luaL_addchar(b, news[i]); + } + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) { + const char *e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ + n++; + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#include + +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) + + +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) + + +/* +** Add integer part of 'x' to buffer and return new 'x' +*/ +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} + + +static int num2straux (char *buff, int sz, lua_Number x) { + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) + + +/* valid flags in a format specification */ +#define FLAGS "-+ #0" + +/* +** maximum size of each format specification (such as "%-099.99d") +*/ +#define MAX_FORMAT 32 + + +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { + luaL_addchar(b, '"'); + while (len--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + + +/* +** Ensures the 'buff' string uses a dot as the radix character. +*/ +static void checkdp (char *buff, int nb) { + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) { /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; + *form = '\0'; + return p; +} + + +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static int str_format (lua_State *L) { + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': case 'i': + case 'o': case 'u': case 'x': case 'X': { + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); + break; + } + case 'a': case 'A': + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': case 'E': case 'f': + case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); + break; + } + case 'q': { + addliteral(L, &b, arg); + break; + } + case 's': { + size_t l; + const char *s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); + } + } + lua_assert(nb < MAX_ITEM); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/libs/lua/source/ltable.c b/libs/lua/source/ltable.c index ea4fe7fc..28499a76 100644 --- a/libs/lua/source/ltable.c +++ b/libs/lua/source/ltable.c @@ -1,688 +1,688 @@ -/* -** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - -#define ltable_c -#define LUA_CORE - -#include "lprefix.h" - - -/* -** Implementation of tables (aka arrays, objects, or hash tables). -** Tables keep its elements in two parts: an array part and a hash part. -** Non-negative integer keys are all candidates to be kept in the array -** part. The actual size of the array is the largest 'n' such that -** more than half the slots between 1 and n are in use. -** Hash uses a mix of chained scatter table with Brent's variation. -** A main invariant of these tables is that, if an element is not -** in its main position (i.e. the 'original' position that its hash gives -** to it), then the colliding element is in its own main position. -** Hence even when the load factor reaches 100%, performance remains good. -*/ - -#include -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lvm.h" - - -/* -** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is -** the largest integer such that MAXASIZE fits in an unsigned int. -*/ -#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) -#define MAXASIZE (1u << MAXABITS) - -/* -** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest -** integer such that 2^MAXHBITS fits in a signed int. (Note that the -** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still -** fits comfortably in an unsigned int.) -*/ -#define MAXHBITS (MAXABITS - 1) - - -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - -#define hashstr(t,str) hashpow2(t, (str)->hash) -#define hashboolean(t,p) hashpow2(t, p) -#define hashint(t,i) hashpow2(t, i) - - -/* -** for some types, it is better to avoid modulus by power of 2, as -** they tend to have many 2 factors. -*/ -#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) - - -#define hashpointer(t,p) hashmod(t, point2uint(p)) - - -#define dummynode (&dummynode_) - -static const Node dummynode_ = { - {NILCONSTANT}, /* value */ - {{NILCONSTANT, 0}} /* key */ -}; - - -/* -** Hash for floating-point numbers. -** The main computation should be just -** n = frexp(n, &i); return (n * INT_MAX) + i -** but there are some numerical subtleties. -** In a two-complement representation, INT_MAX does not has an exact -** representation as a float, but INT_MIN does; because the absolute -** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the -** absolute value of the product 'frexp * -INT_MIN' is smaller or equal -** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when -** adding 'i'; the use of '~u' (instead of '-u') avoids problems with -** INT_MIN. -*/ -#if !defined(l_hashfloat) -static int l_hashfloat (lua_Number n) { - int i; - lua_Integer ni; - n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); - if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ - lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); - return 0; - } - else { /* normal case */ - unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); - return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); - } -} -#endif - - -/* -** returns the 'main' position of an element in a table (that is, the index -** of its hash value) -*/ -static Node *mainposition (const Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TNUMINT: - return hashint(t, ivalue(key)); - case LUA_TNUMFLT: - return hashmod(t, l_hashfloat(fltvalue(key))); - case LUA_TSHRSTR: - return hashstr(t, tsvalue(key)); - case LUA_TLNGSTR: - return hashpow2(t, luaS_hashlongstr(tsvalue(key))); - case LUA_TBOOLEAN: - return hashboolean(t, bvalue(key)); - case LUA_TLIGHTUSERDATA: - return hashpointer(t, pvalue(key)); - case LUA_TLCF: - return hashpointer(t, fvalue(key)); - default: - lua_assert(!ttisdeadkey(key)); - return hashpointer(t, gcvalue(key)); - } -} - - -/* -** returns the index for 'key' if 'key' is an appropriate key to live in -** the array part of the table, 0 otherwise. -*/ -static unsigned int arrayindex (const TValue *key) { - if (ttisinteger(key)) { - lua_Integer k = ivalue(key); - if (0 < k && (lua_Unsigned)k <= MAXASIZE) - return cast(unsigned int, k); /* 'key' is an appropriate array index */ - } - return 0; /* 'key' did not match some condition */ -} - - -/* -** returns the index of a 'key' for table traversals. First goes all -** elements in the array part, then elements in the hash part. The -** beginning of a traversal is signaled by 0. -*/ -static unsigned int findindex (lua_State *L, Table *t, StkId key) { - unsigned int i; - if (ttisnil(key)) return 0; /* first iteration */ - i = arrayindex(key); - if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ - return i; /* yes; that's the index */ - else { - int nx; - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in 'next' */ - if (luaV_rawequalobj(gkey(n), key) || - (ttisdeadkey(gkey(n)) && iscollectable(key) && - deadvalue(gkey(n)) == gcvalue(key))) { - i = cast_int(n - gnode(t, 0)); /* key index in hash table */ - /* hash elements are numbered after array ones */ - return (i + 1) + t->sizearray; - } - nx = gnext(n); - if (nx == 0) - luaG_runerror(L, "invalid key to 'next'"); /* key not found */ - else n += nx; - } - } -} - - -int luaH_next (lua_State *L, Table *t, StkId key) { - unsigned int i = findindex(L, t, key); /* find original element */ - for (; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setivalue(key, i + 1); - setobj2s(L, key+1, &t->array[i]); - return 1; - } - } - for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, gkey(gnode(t, i))); - setobj2s(L, key+1, gval(gnode(t, i))); - return 1; - } - } - return 0; /* no more elements */ -} - - -/* -** {============================================================= -** Rehash -** ============================================================== -*/ - -/* -** Compute the optimal size for the array part of table 't'. 'nums' is a -** "count array" where 'nums[i]' is the number of integers in the table -** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of -** integer keys in the table and leaves with the number of keys that -** will go to the array part; return the optimal size. -*/ -static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { - int i; - unsigned int twotoi; /* 2^i (candidate for optimal size) */ - unsigned int a = 0; /* number of elements smaller than 2^i */ - unsigned int na = 0; /* number of elements to go to array part */ - unsigned int optimal = 0; /* optimal size for array part */ - /* loop while keys can fill more than half of total size */ - for (i = 0, twotoi = 1; - twotoi > 0 && *pna > twotoi / 2; - i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - if (a > twotoi/2) { /* more than half elements present? */ - optimal = twotoi; /* optimal size (till now) */ - na = a; /* all elements up to 'optimal' will go to array part */ - } - } - } - lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); - *pna = na; - return optimal; -} - - -static int countint (const TValue *key, unsigned int *nums) { - unsigned int k = arrayindex(key); - if (k != 0) { /* is 'key' an appropriate array index? */ - nums[luaO_ceillog2(k)]++; /* count as such */ - return 1; - } - else - return 0; -} - - -/* -** Count keys in array part of table 't': Fill 'nums[i]' with -** number of keys that will go into corresponding slice and return -** total number of non-nil keys. -*/ -static unsigned int numusearray (const Table *t, unsigned int *nums) { - int lg; - unsigned int ttlg; /* 2^lg */ - unsigned int ause = 0; /* summation of 'nums' */ - unsigned int i = 1; /* count to traverse all array keys */ - /* traverse each slice */ - for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { - unsigned int lc = 0; /* counter */ - unsigned int lim = ttlg; - if (lim > t->sizearray) { - lim = t->sizearray; /* adjust upper limit */ - if (i > lim) - break; /* no more elements to count */ - } - /* count elements in range (2^(lg - 1), 2^lg] */ - for (; i <= lim; i++) { - if (!ttisnil(&t->array[i-1])) - lc++; - } - nums[lg] += lc; - ause += lc; - } - return ause; -} - - -static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { - int totaluse = 0; /* total number of elements */ - int ause = 0; /* elements added to 'nums' (can go to array part) */ - int i = sizenode(t); - while (i--) { - Node *n = &t->node[i]; - if (!ttisnil(gval(n))) { - ause += countint(gkey(n), nums); - totaluse++; - } - } - *pna += ause; - return totaluse; -} - - -static void setarrayvector (lua_State *L, Table *t, unsigned int size) { - unsigned int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TValue); - for (i=t->sizearray; iarray[i]); - t->sizearray = size; -} - - -static void setnodevector (lua_State *L, Table *t, unsigned int size) { - if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, dummynode); /* use common 'dummynode' */ - t->lsizenode = 0; - t->lastfree = NULL; /* signal that it is using dummy node */ - } - else { - int i; - int lsize = luaO_ceillog2(size); - if (lsize > MAXHBITS) - luaG_runerror(L, "table overflow"); - size = twoto(lsize); - t->node = luaM_newvector(L, size, Node); - for (i = 0; i < (int)size; i++) { - Node *n = gnode(t, i); - gnext(n) = 0; - setnilvalue(wgkey(n)); - setnilvalue(gval(n)); - } - t->lsizenode = cast_byte(lsize); - t->lastfree = gnode(t, size); /* all positions are free */ - } -} - - -typedef struct { - Table *t; - unsigned int nhsize; -} AuxsetnodeT; - - -static void auxsetnode (lua_State *L, void *ud) { - AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); - setnodevector(L, asn->t, asn->nhsize); -} - - -void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize) { - unsigned int i; - int j; - AuxsetnodeT asn; - unsigned int oldasize = t->sizearray; - int oldhsize = allocsizenode(t); - Node *nold = t->node; /* save old hash ... */ - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ - asn.t = t; asn.nhsize = nhsize; - if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ - setarrayvector(L, t, oldasize); /* array back to its original size */ - luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ - } - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; iarray[i])) - luaH_setint(L, t, i + 1, &t->array[i]); - } - /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TValue); - } - /* re-insert elements from hash part */ - for (j = oldhsize - 1; j >= 0; j--) { - Node *old = nold + j; - if (!ttisnil(gval(old))) { - /* doesn't need barrier/invalidate cache, as entry was - already present in the table */ - setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); - } - } - if (oldhsize > 0) /* not the dummy node? */ - luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ -} - - -void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { - int nsize = allocsizenode(t); - luaH_resize(L, t, nasize, nsize); -} - -/* -** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i -*/ -static void rehash (lua_State *L, Table *t, const TValue *ek) { - unsigned int asize; /* optimal size for array part */ - unsigned int na; /* number of keys in the array part */ - unsigned int nums[MAXABITS + 1]; - int i; - int totaluse; - for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ - na = numusearray(t, nums); /* count keys in array part */ - totaluse = na; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, &na); /* count keys in hash part */ - /* count extra key */ - na += countint(ek, nums); - totaluse++; - /* compute new size for array part */ - asize = computesizes(nums, &na); - /* resize the table to new computed sizes */ - luaH_resize(L, t, asize, totaluse - na); -} - - - -/* -** }============================================================= -*/ - - -Table *luaH_new (lua_State *L) { - GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); - Table *t = gco2t(o); - t->metatable = NULL; - t->flags = cast_byte(~0); - t->array = NULL; - t->sizearray = 0; - setnodevector(L, t, 0); - return t; -} - - -void luaH_free (lua_State *L, Table *t) { - if (!isdummy(t)) - luaM_freearray(L, t->node, cast(size_t, sizenode(t))); - luaM_freearray(L, t->array, t->sizearray); - luaM_free(L, t); -} - - -static Node *getfreepos (Table *t) { - if (!isdummy(t)) { - while (t->lastfree > t->node) { - t->lastfree--; - if (ttisnil(gkey(t->lastfree))) - return t->lastfree; - } - } - return NULL; /* could not find a free place */ -} - - - -/* -** inserts a new key into a hash table; first, check whether key's main -** position is free. If not, check whether colliding node is in its main -** position or not: if it is not, move colliding node to an empty place and -** put new key in its main position; otherwise (colliding node is in its main -** position), new key goes to an empty position. -*/ -TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { - Node *mp; - TValue aux; - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisfloat(key)) { - lua_Integer k; - if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */ - setivalue(&aux, k); - key = &aux; /* insert it as an integer */ - } - else if (luai_numisnan(fltvalue(key))) - luaG_runerror(L, "table index is NaN"); - } - mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ - Node *othern; - Node *f = getfreepos(t); /* get a free place */ - if (f == NULL) { /* cannot find a free place? */ - rehash(L, t, key); /* grow table */ - /* whatever called 'newkey' takes care of TM cache */ - return luaH_set(L, t, key); /* insert key into grown table */ - } - lua_assert(!isdummy(t)); - othern = mainposition(t, gkey(mp)); - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (othern + gnext(othern) != mp) /* find previous */ - othern += gnext(othern); - gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ - *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - if (gnext(mp) != 0) { - gnext(f) += cast_int(mp - f); /* correct 'next' */ - gnext(mp) = 0; /* now 'mp' is free */ - } - setnilvalue(gval(mp)); - } - else { /* colliding node is in its own main position */ - /* new node will go into free position */ - if (gnext(mp) != 0) - gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ - else lua_assert(gnext(f) == 0); - gnext(mp) = cast_int(f - mp); - mp = f; - } - } - setnodekey(L, &mp->i_key, key); - luaC_barrierback(L, t, key); - lua_assert(ttisnil(gval(mp))); - return gval(mp); -} - - -/* -** search function for integers -*/ -const TValue *luaH_getint (Table *t, lua_Integer key) { - /* (1 <= key && key <= t->sizearray) */ - if (l_castS2U(key) - 1 < t->sizearray) - return &t->array[key - 1]; - else { - Node *n = hashint(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) break; - n += nx; - } - } - return luaO_nilobject; - } -} - - -/* -** search function for short strings -*/ -const TValue *luaH_getshortstr (Table *t, TString *key) { - Node *n = hashstr(t, key); - lua_assert(key->tt == LUA_TSHRSTR); - for (;;) { /* check whether 'key' is somewhere in the chain */ - const TValue *k = gkey(n); - if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) - return luaO_nilobject; /* not found */ - n += nx; - } - } -} - - -/* -** "Generic" get version. (Not that generic: not valid for integers, -** which may be in array part, nor for floats with integral values.) -*/ -static const TValue *getgeneric (Table *t, const TValue *key) { - Node *n = mainposition(t, key); - for (;;) { /* check whether 'key' is somewhere in the chain */ - if (luaV_rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else { - int nx = gnext(n); - if (nx == 0) - return luaO_nilobject; /* not found */ - n += nx; - } - } -} - - -const TValue *luaH_getstr (Table *t, TString *key) { - if (key->tt == LUA_TSHRSTR) - return luaH_getshortstr(t, key); - else { /* for long strings, use generic case */ - TValue ko; - setsvalue(cast(lua_State *, NULL), &ko, key); - return getgeneric(t, &ko); - } -} - - -/* -** main search function -*/ -const TValue *luaH_get (Table *t, const TValue *key) { - switch (ttype(key)) { - case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); - case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); - case LUA_TNIL: return luaO_nilobject; - case LUA_TNUMFLT: { - lua_Integer k; - if (luaV_tointeger(key, &k, 0)) /* index is int? */ - return luaH_getint(t, k); /* use specialized version */ - /* else... */ - } /* FALLTHROUGH */ - default: - return getgeneric(t, key); - } -} - - -/* -** beware: when using this function you probably need to check a GC -** barrier and invalidate the TM cache. -*/ -TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { - const TValue *p = luaH_get(t, key); - if (p != luaO_nilobject) - return cast(TValue *, p); - else return luaH_newkey(L, t, key); -} - - -void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { - const TValue *p = luaH_getint(t, key); - TValue *cell; - if (p != luaO_nilobject) - cell = cast(TValue *, p); - else { - TValue k; - setivalue(&k, key); - cell = luaH_newkey(L, t, &k); - } - setobj2t(L, cell, value); -} - - -static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { - lua_Unsigned i = j; /* i is zero or a present index */ - j++; - /* find 'i' and 'j' such that i is present and j is not */ - while (!ttisnil(luaH_getint(t, j))) { - i = j; - if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while (!ttisnil(luaH_getint(t, i))) i++; - return i - 1; - } - j *= 2; - } - /* now do a binary search between them */ - while (j - i > 1) { - lua_Unsigned m = (i+j)/2; - if (ttisnil(luaH_getint(t, m))) j = m; - else i = m; - } - return i; -} - - -/* -** Try to find a boundary in table 't'. A 'boundary' is an integer index -** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). -*/ -lua_Unsigned luaH_getn (Table *t) { - unsigned int j = t->sizearray; - if (j > 0 && ttisnil(&t->array[j - 1])) { - /* there is a boundary in the array part: (binary) search for it */ - unsigned int i = 0; - while (j - i > 1) { - unsigned int m = (i+j)/2; - if (ttisnil(&t->array[m - 1])) j = m; - else i = m; - } - return i; - } - /* else must find a boundary in hash part */ - else if (isdummy(t)) /* hash part is empty? */ - return j; /* that is easy... */ - else return unbound_search(t, j); -} - - - -#if defined(LUA_DEBUG) - -Node *luaH_mainposition (const Table *t, const TValue *key) { - return mainposition(t, key); -} - -int luaH_isdummy (const Table *t) { return isdummy(t); } - -#endif +/* +** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + + +/* +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the 'original' position that its hash gives +** to it), then the colliding element is in its own main position. +** Hence even when the load factor reaches 100%, performance remains good. +*/ + +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "lvm.h" + + +/* +** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is +** the largest integer such that MAXASIZE fits in an unsigned int. +*/ +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) +#define MAXASIZE (1u << MAXABITS) + +/* +** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest +** integer such that 2^MAXHBITS fits in a signed int. (Note that the +** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still +** fits comfortably in an unsigned int.) +*/ +#define MAXHBITS (MAXABITS - 1) + + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashstr(t,str) hashpow2(t, (str)->hash) +#define hashboolean(t,p) hashpow2(t, p) +#define hashint(t,i) hashpow2(t, i) + + +/* +** for some types, it is better to avoid modulus by power of 2, as +** they tend to have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashpointer(t,p) hashmod(t, point2uint(p)) + + +#define dummynode (&dummynode_) + +static const Node dummynode_ = { + {NILCONSTANT}, /* value */ + {{NILCONSTANT, 0}} /* key */ +}; + + +/* +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. +*/ +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { + int i; + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); + return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); + } +} +#endif + + +/* +** returns the 'main' position of an element in a table (that is, the index +** of its hash value) +*/ +static Node *mainposition (const Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TNUMINT: + return hashint(t, ivalue(key)); + case LUA_TNUMFLT: + return hashmod(t, l_hashfloat(fltvalue(key))); + case LUA_TSHRSTR: + return hashstr(t, tsvalue(key)); + case LUA_TLNGSTR: + return hashpow2(t, luaS_hashlongstr(tsvalue(key))); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + case LUA_TLCF: + return hashpointer(t, fvalue(key)); + default: + lua_assert(!ttisdeadkey(key)); + return hashpointer(t, gcvalue(key)); + } +} + + +/* +** returns the index for 'key' if 'key' is an appropriate key to live in +** the array part of the table, 0 otherwise. +*/ +static unsigned int arrayindex (const TValue *key) { + if (ttisinteger(key)) { + lua_Integer k = ivalue(key); + if (0 < k && (lua_Unsigned)k <= MAXASIZE) + return cast(unsigned int, k); /* 'key' is an appropriate array index */ + } + return 0; /* 'key' did not match some condition */ +} + + +/* +** returns the index of a 'key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning of a traversal is signaled by 0. +*/ +static unsigned int findindex (lua_State *L, Table *t, StkId key) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ + i = arrayindex(key); + if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ + else { + int nx; + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in 'next' */ + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && + deadvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return (i + 1) + t->sizearray; + } + nx = gnext(n); + if (nx == 0) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + else n += nx; + } + } +} + + +int luaH_next (lua_State *L, Table *t, StkId key) { + unsigned int i = findindex(L, t, key); /* find original element */ + for (; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setivalue(key, i + 1); + setobj2s(L, key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ +} + + +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { + int i; + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; + twotoi > 0 && *pna > twotoi / 2; + i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ + } + } + } + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; +} + + +static int countint (const TValue *key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ + nums[luaO_ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; +} + + +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { + int lg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg - 1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; +} + + +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ + int i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!ttisnil(gval(n))) { + ause += countint(gkey(n), nums); + totaluse++; + } + } + *pna += ause; + return totaluse; +} + + +static void setarrayvector (lua_State *L, Table *t, unsigned int size) { + unsigned int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; +} + + +static void setnodevector (lua_State *L, Table *t, unsigned int size) { + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ + t->lsizenode = 0; + t->lastfree = NULL; /* signal that it is using dummy node */ + } + else { + int i; + int lsize = luaO_ceillog2(size); + if (lsize > MAXHBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + t->node = luaM_newvector(L, size, Node); + for (i = 0; i < (int)size; i++) { + Node *n = gnode(t, i); + gnext(n) = 0; + setnilvalue(wgkey(n)); + setnilvalue(gval(n)); + } + t->lsizenode = cast_byte(lsize); + t->lastfree = gnode(t, size); /* all positions are free */ + } +} + + +typedef struct { + Table *t; + unsigned int nhsize; +} AuxsetnodeT; + + +static void auxsetnode (lua_State *L, void *ud) { + AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); + setnodevector(L, asn->t, asn->nhsize); +} + + +void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize) { + unsigned int i; + int j; + AuxsetnodeT asn; + unsigned int oldasize = t->sizearray; + int oldhsize = allocsizenode(t); + Node *nold = t->node; /* save old hash ... */ + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + asn.t = t; asn.nhsize = nhsize; + if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ + setarrayvector(L, t, oldasize); /* array back to its original size */ + luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ + } + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + luaH_setint(L, t, i + 1, &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + } + /* re-insert elements from hash part */ + for (j = oldhsize - 1; j >= 0; j--) { + Node *old = nold + j; + if (!ttisnil(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); + } + } + if (oldhsize > 0) /* not the dummy node? */ + luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ +} + + +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { + int nsize = allocsizenode(t); + luaH_resize(L, t, nasize, nsize); +} + +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ +static void rehash (lua_State *L, Table *t, const TValue *ek) { + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; + int i; + int totaluse; + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ + /* count extra key */ + na += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + asize = computesizes(nums, &na); + /* resize the table to new computed sizes */ + luaH_resize(L, t, asize, totaluse - na); +} + + + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L) { + GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); + Table *t = gco2t(o); + t->metatable = NULL; + t->flags = cast_byte(~0); + t->array = NULL; + t->sizearray = 0; + setnodevector(L, t, 0); + return t; +} + + +void luaH_free (lua_State *L, Table *t) { + if (!isdummy(t)) + luaM_freearray(L, t->node, cast(size_t, sizenode(t))); + luaM_freearray(L, t->array, t->sizearray); + luaM_free(L, t); +} + + +static Node *getfreepos (Table *t) { + if (!isdummy(t)) { + while (t->lastfree > t->node) { + t->lastfree--; + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + } + return NULL; /* could not find a free place */ +} + + + +/* +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. +*/ +TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp; + TValue aux; + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisfloat(key)) { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (luai_numisnan(fltvalue(key))) + luaG_runerror(L, "table index is NaN"); + } + mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ + Node *othern; + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + /* whatever called 'newkey' takes care of TM cache */ + return luaH_set(L, t, key); /* insert key into grown table */ + } + lua_assert(!isdummy(t)); + othern = mainposition(t, gkey(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } + setnilvalue(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; + } + } + setnodekey(L, &mp->i_key, key); + luaC_barrierback(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); +} + + +/* +** search function for integers +*/ +const TValue *luaH_getint (Table *t, lua_Integer key) { + /* (1 <= key && key <= t->sizearray) */ + if (l_castS2U(key) - 1 < t->sizearray) + return &t->array[key - 1]; + else { + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } + return luaO_nilobject; + } +} + + +/* +** search function for short strings +*/ +const TValue *luaH_getshortstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + lua_assert(key->tt == LUA_TSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + const TValue *k = gkey(n); + if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +*/ +static const TValue *getgeneric (Table *t, const TValue *key) { + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_TSHRSTR) + return luaH_getshortstr(t, key); + else { /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko); + } +} + + +/* +** main search function +*/ +const TValue *luaH_get (Table *t, const TValue *key) { + switch (ttype(key)) { + case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); + case LUA_TNIL: return luaO_nilobject; + case LUA_TNUMFLT: { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) /* index is int? */ + return luaH_getint(t, k); /* use specialized version */ + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key); + } +} + + +/* +** beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); + if (p != luaO_nilobject) + return cast(TValue *, p); + else return luaH_newkey(L, t, key); +} + + +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { + const TValue *p = luaH_getint(t, key); + TValue *cell; + if (p != luaO_nilobject) + cell = cast(TValue *, p); + else { + TValue k; + setivalue(&k, key); + cell = luaH_newkey(L, t, &k); + } + setobj2t(L, cell, value); +} + + +static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { + lua_Unsigned i = j; /* i is zero or a present index */ + j++; + /* find 'i' and 'j' such that i is present and j is not */ + while (!ttisnil(luaH_getint(t, j))) { + i = j; + if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getint(t, i))) i++; + return i - 1; + } + j *= 2; + } + /* now do a binary search between them */ + while (j - i > 1) { + lua_Unsigned m = (i+j)/2; + if (ttisnil(luaH_getint(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table 't'. A 'boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +lua_Unsigned luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (isdummy(t)) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (const Table *t) { return isdummy(t); } + +#endif diff --git a/libs/lua/source/ltablib.c b/libs/lua/source/ltablib.c index c5349578..395b8e74 100644 --- a/libs/lua/source/ltablib.c +++ b/libs/lua/source/ltablib.c @@ -1,450 +1,450 @@ -/* -** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - -#define ltablib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** Operations that an object must define to mimic a table -** (some functions only need some of them) -*/ -#define TAB_R 1 /* read */ -#define TAB_W 2 /* write */ -#define TAB_L 4 /* length */ -#define TAB_RW (TAB_R | TAB_W) /* read/write */ - - -#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) - - -static int checkfield (lua_State *L, const char *key, int n) { - lua_pushstring(L, key); - return (lua_rawget(L, -n) != LUA_TNIL); -} - - -/* -** Check that 'arg' either is a table or can behave like one (that is, -** has a metatable with the required metamethods) -*/ -static void checktab (lua_State *L, int arg, int what) { - if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ - int n = 1; /* number of elements to pop */ - if (lua_getmetatable(L, arg) && /* must have metatable */ - (!(what & TAB_R) || checkfield(L, "__index", ++n)) && - (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && - (!(what & TAB_L) || checkfield(L, "__len", ++n))) { - lua_pop(L, n); /* pop metatable and tested metamethods */ - } - else - luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ - } -} - - -#if defined(LUA_COMPAT_MAXN) -static int maxn (lua_State *L) { - lua_Number max = 0; - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1)) { - lua_pop(L, 1); /* remove value */ - if (lua_type(L, -1) == LUA_TNUMBER) { - lua_Number v = lua_tonumber(L, -1); - if (v > max) max = v; - } - } - lua_pushnumber(L, max); - return 1; -} -#endif - - -static int tinsert (lua_State *L) { - lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ - lua_Integer pos; /* where to insert new element */ - switch (lua_gettop(L)) { - case 2: { /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - break; - } - case 3: { - lua_Integer i; - pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ - luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); - for (i = e; i > pos; i--) { /* move up elements */ - lua_geti(L, 1, i - 1); - lua_seti(L, 1, i); /* t[i] = t[i - 1] */ - } - break; - } - default: { - return luaL_error(L, "wrong number of arguments to 'insert'"); - } - } - lua_seti(L, 1, pos); /* t[pos] = v */ - return 0; -} - - -static int tremove (lua_State *L) { - lua_Integer size = aux_getn(L, 1, TAB_RW); - lua_Integer pos = luaL_optinteger(L, 2, size); - if (pos != size) /* validate 'pos' if given */ - luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - lua_geti(L, 1, pos); /* result = t[pos] */ - for ( ; pos < size; pos++) { - lua_geti(L, 1, pos + 1); - lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ - } - lua_pushnil(L); - lua_seti(L, 1, pos); /* t[pos] = nil */ - return 1; -} - - -/* -** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever -** possible, copy in increasing order, which is better for rehashing. -** "possible" means destination after original range, or smaller -** than origin, or copying to another table. -*/ -static int tmove (lua_State *L) { - lua_Integer f = luaL_checkinteger(L, 2); - lua_Integer e = luaL_checkinteger(L, 3); - lua_Integer t = luaL_checkinteger(L, 4); - int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ - checktab(L, 1, TAB_R); - checktab(L, tt, TAB_W); - if (e >= f) { /* otherwise, nothing to move */ - lua_Integer n, i; - luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, - "too many elements to move"); - n = e - f + 1; /* number of elements to move */ - luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, - "destination wrap around"); - if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { - for (i = 0; i < n; i++) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - else { - for (i = n - 1; i >= 0; i--) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - } - lua_pushvalue(L, tt); /* return destination table */ - return 1; -} - - -static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { - lua_geti(L, 1, i); - if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", - luaL_typename(L, -1), i); - luaL_addvalue(b); -} - - -static int tconcat (lua_State *L) { - luaL_Buffer b; - lua_Integer last = aux_getn(L, 1, TAB_R); - size_t lsep; - const char *sep = luaL_optlstring(L, 2, "", &lsep); - lua_Integer i = luaL_optinteger(L, 3, 1); - last = luaL_optinteger(L, 4, last); - luaL_buffinit(L, &b); - for (; i < last; i++) { - addfield(L, &b, i); - luaL_addlstring(&b, sep, lsep); - } - if (i == last) /* add last value (if interval was not empty) */ - addfield(L, &b, i); - luaL_pushresult(&b); - return 1; -} - - -/* -** {====================================================== -** Pack/unpack -** ======================================================= -*/ - -static int pack (lua_State *L) { - int i; - int n = lua_gettop(L); /* number of elements to pack */ - lua_createtable(L, n, 1); /* create result table */ - lua_insert(L, 1); /* put it at index 1 */ - for (i = n; i >= 1; i--) /* assign elements */ - lua_seti(L, 1, i); - lua_pushinteger(L, n); - lua_setfield(L, 1, "n"); /* t.n = number of elements */ - return 1; /* return table */ -} - - -static int unpack (lua_State *L) { - lua_Unsigned n; - lua_Integer i = luaL_optinteger(L, 2, 1); - lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); - if (i > e) return 0; /* empty range */ - n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ - if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) - return luaL_error(L, "too many results to unpack"); - for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ - lua_geti(L, 1, i); - } - lua_geti(L, 1, e); /* push last element */ - return (int)n; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Quicksort -** (based on 'Algorithms in MODULA-3', Robert Sedgewick; -** Addison-Wesley, 1993.) -** ======================================================= -*/ - - -/* type for array indices */ -typedef unsigned int IdxT; - - -/* -** Produce a "random" 'unsigned int' to randomize pivot choice. This -** macro is used only when 'sort' detects a big imbalance in the result -** of a partition. (If you don't want/need this "randomness", ~0 is a -** good choice.) -*/ -#if !defined(l_randomizePivot) /* { */ - -#include - -/* size of 'e' measured in number of 'unsigned int's */ -#define sof(e) (sizeof(e) / sizeof(unsigned int)) - -/* -** Use 'time' and 'clock' as sources of "randomness". Because we don't -** know the types 'clock_t' and 'time_t', we cannot cast them to -** anything without risking overflows. A safe way to use their values -** is to copy them to an array of a known type and use the array values. -*/ -static unsigned int l_randomizePivot (void) { - clock_t c = clock(); - time_t t = time(NULL); - unsigned int buff[sof(c) + sof(t)]; - unsigned int i, rnd = 0; - memcpy(buff, &c, sof(c) * sizeof(unsigned int)); - memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); - for (i = 0; i < sof(buff); i++) - rnd += buff[i]; - return rnd; -} - -#endif /* } */ - - -/* arrays larger than 'RANLIMIT' may use randomized pivots */ -#define RANLIMIT 100u - - -static void set2 (lua_State *L, IdxT i, IdxT j) { - lua_seti(L, 1, i); - lua_seti(L, 1, j); -} - - -/* -** Return true iff value at stack index 'a' is less than the value at -** index 'b' (according to the order of the sort). -*/ -static int sort_comp (lua_State *L, int a, int b) { - if (lua_isnil(L, 2)) /* no function? */ - return lua_compare(L, a, b, LUA_OPLT); /* a < b */ - else { /* function */ - int res; - lua_pushvalue(L, 2); /* push function */ - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua_call(L, 2, 1); /* call function */ - res = lua_toboolean(L, -1); /* get result */ - lua_pop(L, 1); /* pop result */ - return res; - } -} - - -/* -** Does the partition: Pivot P is at the top of the stack. -** precondition: a[lo] <= P == a[up-1] <= a[up], -** so it only needs to do the partition from lo + 1 to up - 2. -** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] -** returns 'i'. -*/ -static IdxT partition (lua_State *L, IdxT lo, IdxT up) { - IdxT i = lo; /* will be incremented before first use */ - IdxT j = up - 1; /* will be decremented before first use */ - /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ - for (;;) { - /* next loop: repeat ++i while a[i] < P */ - while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ - /* next loop: repeat --j while P < a[j] */ - while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j < i) /* j < i but a[j] > P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ - if (j < i) { /* no elements out of place? */ - /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ - lua_pop(L, 1); /* pop a[j] */ - /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ - set2(L, up - 1, i); - return i; - } - /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ - set2(L, i, j); - } -} - - -/* -** Choose an element in the middle (2nd-3th quarters) of [lo,up] -** "randomized" by 'rnd' -*/ -static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { - IdxT r4 = (up - lo) / 4; /* range/4 */ - IdxT p = rnd % (r4 * 2) + (lo + r4); - lua_assert(lo + r4 <= p && p <= up - r4); - return p; -} - - -/* -** QuickSort algorithm (recursive function) -*/ -static void auxsort (lua_State *L, IdxT lo, IdxT up, - unsigned int rnd) { - while (lo < up) { /* loop for tail recursion */ - IdxT p; /* Pivot index */ - IdxT n; /* to be used later */ - /* sort elements 'lo', 'p', and 'up' */ - lua_geti(L, 1, lo); - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ - set2(L, lo, up); /* swap a[lo] - a[up] */ - else - lua_pop(L, 2); /* remove both values */ - if (up - lo == 1) /* only 2 elements? */ - return; /* already sorted */ - if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ - p = (lo + up)/2; /* middle element is a good pivot */ - else /* for larger intervals, it is worth a random pivot */ - p = choosePivot(lo, up, rnd); - lua_geti(L, 1, p); - lua_geti(L, 1, lo); - if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ - set2(L, p, lo); /* swap a[p] - a[lo] */ - else { - lua_pop(L, 1); /* remove a[lo] */ - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ - set2(L, p, up); /* swap a[up] - a[p] */ - else - lua_pop(L, 2); - } - if (up - lo == 2) /* only 3 elements? */ - return; /* already sorted */ - lua_geti(L, 1, p); /* get middle element (Pivot) */ - lua_pushvalue(L, -1); /* push Pivot */ - lua_geti(L, 1, up - 1); /* push a[up - 1] */ - set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ - p = partition(L, lo, up); - /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ - if (p - lo < up - p) { /* lower interval is smaller? */ - auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ - n = p - lo; /* size of smaller interval */ - lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ - } - else { - auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ - n = up - p; /* size of smaller interval */ - up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ - } - if ((up - lo) / 128 > n) /* partition too imbalanced? */ - rnd = l_randomizePivot(); /* try a new randomization */ - } /* tail call auxsort(L, lo, up, rnd) */ -} - - -static int sort (lua_State *L) { - lua_Integer n = aux_getn(L, 1, TAB_RW); - if (n > 1) { /* non-trivial interval? */ - luaL_argcheck(L, n < INT_MAX, 1, "array too big"); - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ - lua_settop(L, 2); /* make sure there are two arguments */ - auxsort(L, 1, (IdxT)n, 0); - } - return 0; -} - -/* }====================================================== */ - - -static const luaL_Reg tab_funcs[] = { - {"concat", tconcat}, -#if defined(LUA_COMPAT_MAXN) - {"maxn", maxn}, -#endif - {"insert", tinsert}, - {"pack", pack}, - {"unpack", unpack}, - {"remove", tremove}, - {"move", tmove}, - {"sort", sort}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_table (lua_State *L) { - luaL_newlib(L, tab_funcs); -#if defined(LUA_COMPAT_UNPACK) - /* _G.unpack = table.unpack */ - lua_getfield(L, -1, "unpack"); - lua_setglobal(L, "unpack"); -#endif - return 1; -} - +/* +** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + +#define ltablib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} + + +#if defined(LUA_COMPAT_MAXN) +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; +} +#endif + + +static int tinsert (lua_State *L) { + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); + for (i = e; i > pos; i--) { /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for ( ; pos < size; pos++) { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* t[pos] = nil */ + return 1; +} + + +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); + if (!lua_isstring(L, -1)) + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); + luaL_addvalue(b); +} + + +static int tconcat (lua_State *L) { + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char *sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; +} + + +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int pack (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ +} + + +static int unpack (lua_State *L) { + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Quicksort +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +** ======================================================= +*/ + + +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ +static int sort_comp (lua_State *L, int a, int b) { + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } +} + + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* remove both values */ + if (up - lo == 1) /* only 2 elements? */ + return; /* already sorted */ + if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ + p = (lo + up)/2; /* middle element is a good pivot */ + else /* for larger intervals, it is worth a random pivot */ + p = choosePivot(lo, up, rnd); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); + if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ + set2(L, p, lo); /* swap a[p] - a[lo] */ + else { + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ + set2(L, p, up); /* swap a[up] - a[p] */ + else + lua_pop(L, 2); + } + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) { /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ + } + else { + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ + } + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ +} + + +static int sort (lua_State *L) { + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; +} + +/* }====================================================== */ + + +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, +#if defined(LUA_COMPAT_MAXN) + {"maxn", maxn}, +#endif + {"insert", tinsert}, + {"pack", pack}, + {"unpack", unpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_table (lua_State *L) { + luaL_newlib(L, tab_funcs); +#if defined(LUA_COMPAT_UNPACK) + /* _G.unpack = table.unpack */ + lua_getfield(L, -1, "unpack"); + lua_setglobal(L, "unpack"); +#endif + return 1; +} + diff --git a/libs/lua/source/ltm.c b/libs/lua/source/ltm.c index 0e7c7132..95de7ad3 100644 --- a/libs/lua/source/ltm.c +++ b/libs/lua/source/ltm.c @@ -1,165 +1,165 @@ -/* -** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $ -** Tag methods -** See Copyright Notice in lua.h -*/ - -#define ltm_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - -static const char udatatypename[] = "userdata"; - -LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { - "no value", - "nil", "boolean", udatatypename, "number", - "string", "table", "function", udatatypename, "thread", - "proto" /* this last case is used for tests only */ -}; - - -void luaT_init (lua_State *L) { - static const char *const luaT_eventname[] = { /* ORDER TM */ - "__index", "__newindex", - "__gc", "__mode", "__len", "__eq", - "__add", "__sub", "__mul", "__mod", "__pow", - "__div", "__idiv", - "__band", "__bor", "__bxor", "__shl", "__shr", - "__unm", "__bnot", "__lt", "__le", - "__concat", "__call" - }; - int i; - for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); - luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ - } -} - - -/* -** function to be used with macro "fasttm": optimized for absence of -** tag methods -*/ -const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { - const TValue *tm = luaH_getshortstr(events, ename); - lua_assert(event <= TM_EQ); - if (ttisnil(tm)) { /* no tag method? */ - events->flags |= cast_byte(1u<metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(o)->metatable; - break; - default: - mt = G(L)->mt[ttnov(o)]; - } - return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); -} - - -/* -** Return the name of the type of an object. For tables and userdata -** with metatable, use their '__name' metafield, if present. -*/ -const char *luaT_objtypename (lua_State *L, const TValue *o) { - Table *mt; - if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || - (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { - const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); - if (ttisstring(name)) /* is '__name' a string? */ - return getstr(tsvalue(name)); /* use it as type name */ - } - return ttypename(ttnov(o)); /* else use standard type name */ -} - - -void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); - StkId func = L->top; - setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ - setobj2s(L, func + 1, p1); /* 1st argument */ - setobj2s(L, func + 2, p2); /* 2nd argument */ - L->top += 3; - if (!hasres) /* no result? 'p3' is third argument */ - setobj2s(L, L->top++, p3); /* 3rd argument */ - /* metamethod may yield only when called from Lua code */ - if (isLua(L->ci)) - luaD_call(L, func, hasres); - else - luaD_callnoyield(L, func, hasres); - if (hasres) { /* if has result, move it to its place */ - p3 = restorestack(L, result); - setobjs2s(L, p3, --L->top); - } -} - - -int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttisnil(tm)) return 0; - luaT_callTM(L, tm, p1, p2, res, 1); - return 1; -} - - -void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - if (!luaT_callbinTM(L, p1, p2, res, event)) { - switch (event) { - case TM_CONCAT: - luaG_concaterror(L, p1, p2); - /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ - case TM_BAND: case TM_BOR: case TM_BXOR: - case TM_SHL: case TM_SHR: case TM_BNOT: { - lua_Number dummy; - if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) - luaG_tointerror(L, p1, p2); - else - luaG_opinterror(L, p1, p2, "perform bitwise operation on"); - } - /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ - default: - luaG_opinterror(L, p1, p2, "perform arithmetic on"); - } - } -} - - -int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, - TMS event) { - if (!luaT_callbinTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else - return !l_isfalse(L->top); -} - +/* +** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#define ltm_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +static const char udatatypename[] = "userdata"; + +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", + "proto" /* this last case is used for tests only */ +}; + + +void luaT_init (lua_State *L) { + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__len", "__eq", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ + } +} + + +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getshortstr(events, ename); + lua_assert(event <= TM_EQ); + if (ttisnil(tm)) { /* no tag method? */ + events->flags |= cast_byte(1u<metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(o)->metatable; + break; + default: + mt = G(L)->mt[ttnov(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + + +/* +** Return the name of the type of an object. For tables and userdata +** with metatable, use their '__name' metafield, if present. +*/ +const char *luaT_objtypename (lua_State *L, const TValue *o) { + Table *mt; + if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || + (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { + const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); + if (ttisstring(name)) /* is '__name' a string? */ + return getstr(tsvalue(name)); /* use it as type name */ + } + return ttypename(ttnov(o)); /* else use standard type name */ +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + StkId func = L->top; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top += 3; + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ + /* metamethod may yield only when called from Lua code */ + if (isLua(L->ci)) + luaD_call(L, func, hasres); + else + luaD_callnoyield(L, func, hasres); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } +} + + +int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + luaT_callTM(L, tm, p1, p2, res, 1); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (!luaT_callbinTM(L, p1, p2, res, event)) { + switch (event) { + case TM_CONCAT: + luaG_concaterror(L, p1, p2); + /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + lua_Number dummy; + if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (!luaT_callbinTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); +} + diff --git a/libs/lua/source/lundump.c b/libs/lua/source/lundump.c index 7a67d75a..2965e3c6 100644 --- a/libs/lua/source/lundump.c +++ b/libs/lua/source/lundump.c @@ -1,279 +1,279 @@ -/* -** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#define lundump_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstring.h" -#include "lundump.h" -#include "lzio.h" - - -#if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) /* empty */ -#endif - - -typedef struct { - lua_State *L; - ZIO *Z; - const char *name; -} LoadState; - - -static l_noret error(LoadState *S, const char *why) { - luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); - luaD_throw(S->L, LUA_ERRSYNTAX); -} - - -/* -** All high-level loads go through LoadVector; you can change it to -** adapt to the endianness of the input -*/ -#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) - -static void LoadBlock (LoadState *S, void *b, size_t size) { - if (luaZ_read(S->Z, b, size) != 0) - error(S, "truncated"); -} - - -#define LoadVar(S,x) LoadVector(S,&x,1) - - -static lu_byte LoadByte (LoadState *S) { - lu_byte x; - LoadVar(S, x); - return x; -} - - -static int LoadInt (LoadState *S) { - int x; - LoadVar(S, x); - return x; -} - - -static lua_Number LoadNumber (LoadState *S) { - lua_Number x; - LoadVar(S, x); - return x; -} - - -static lua_Integer LoadInteger (LoadState *S) { - lua_Integer x; - LoadVar(S, x); - return x; -} - - -static TString *LoadString (LoadState *S) { - size_t size = LoadByte(S); - if (size == 0xFF) - LoadVar(S, size); - if (size == 0) - return NULL; - else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ - char buff[LUAI_MAXSHORTLEN]; - LoadVector(S, buff, size); - return luaS_newlstr(S->L, buff, size); - } - else { /* long string */ - TString *ts = luaS_createlngstrobj(S->L, size); - LoadVector(S, getstr(ts), size); /* load directly in final place */ - return ts; - } -} - - -static void LoadCode (LoadState *S, Proto *f) { - int n = LoadInt(S); - f->code = luaM_newvector(S->L, n, Instruction); - f->sizecode = n; - LoadVector(S, f->code, n); -} - - -static void LoadFunction(LoadState *S, Proto *f, TString *psource); - - -static void LoadConstants (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->k = luaM_newvector(S->L, n, TValue); - f->sizek = n; - for (i = 0; i < n; i++) - setnilvalue(&f->k[i]); - for (i = 0; i < n; i++) { - TValue *o = &f->k[i]; - int t = LoadByte(S); - switch (t) { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o, LoadByte(S)); - break; - case LUA_TNUMFLT: - setfltvalue(o, LoadNumber(S)); - break; - case LUA_TNUMINT: - setivalue(o, LoadInteger(S)); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - setsvalue2n(S->L, o, LoadString(S)); - break; - default: - lua_assert(0); - } - } -} - - -static void LoadProtos (LoadState *S, Proto *f) { - int i; - int n = LoadInt(S); - f->p = luaM_newvector(S->L, n, Proto *); - f->sizep = n; - for (i = 0; i < n; i++) - f->p[i] = NULL; - for (i = 0; i < n; i++) { - f->p[i] = luaF_newproto(S->L); - LoadFunction(S, f->p[i], f->source); - } -} - - -static void LoadUpvalues (LoadState *S, Proto *f) { - int i, n; - n = LoadInt(S); - f->upvalues = luaM_newvector(S->L, n, Upvaldesc); - f->sizeupvalues = n; - for (i = 0; i < n; i++) - f->upvalues[i].name = NULL; - for (i = 0; i < n; i++) { - f->upvalues[i].instack = LoadByte(S); - f->upvalues[i].idx = LoadByte(S); - } -} - - -static void LoadDebug (LoadState *S, Proto *f) { - int i, n; - n = LoadInt(S); - f->lineinfo = luaM_newvector(S->L, n, int); - f->sizelineinfo = n; - LoadVector(S, f->lineinfo, n); - n = LoadInt(S); - f->locvars = luaM_newvector(S->L, n, LocVar); - f->sizelocvars = n; - for (i = 0; i < n; i++) - f->locvars[i].varname = NULL; - for (i = 0; i < n; i++) { - f->locvars[i].varname = LoadString(S); - f->locvars[i].startpc = LoadInt(S); - f->locvars[i].endpc = LoadInt(S); - } - n = LoadInt(S); - for (i = 0; i < n; i++) - f->upvalues[i].name = LoadString(S); -} - - -static void LoadFunction (LoadState *S, Proto *f, TString *psource) { - f->source = LoadString(S); - if (f->source == NULL) /* no source in dump? */ - f->source = psource; /* reuse parent's source */ - f->linedefined = LoadInt(S); - f->lastlinedefined = LoadInt(S); - f->numparams = LoadByte(S); - f->is_vararg = LoadByte(S); - f->maxstacksize = LoadByte(S); - LoadCode(S, f); - LoadConstants(S, f); - LoadUpvalues(S, f); - LoadProtos(S, f); - LoadDebug(S, f); -} - - -static void checkliteral (LoadState *S, const char *s, const char *msg) { - char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ - size_t len = strlen(s); - LoadVector(S, buff, len); - if (memcmp(s, buff, len) != 0) - error(S, msg); -} - - -static void fchecksize (LoadState *S, size_t size, const char *tname) { - if (LoadByte(S) != size) - error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); -} - - -#define checksize(S,t) fchecksize(S,sizeof(t),#t) - -static void checkHeader (LoadState *S) { - checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ - if (LoadByte(S) != LUAC_VERSION) - error(S, "version mismatch in"); - if (LoadByte(S) != LUAC_FORMAT) - error(S, "format mismatch in"); - checkliteral(S, LUAC_DATA, "corrupted"); - checksize(S, int); - checksize(S, size_t); - checksize(S, Instruction); - checksize(S, lua_Integer); - checksize(S, lua_Number); - if (LoadInteger(S) != LUAC_INT) - error(S, "endianness mismatch in"); - if (LoadNumber(S) != LUAC_NUM) - error(S, "float format mismatch in"); -} - - -/* -** load precompiled chunk -*/ -LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { - LoadState S; - LClosure *cl; - if (*name == '@' || *name == '=') - S.name = name + 1; - else if (*name == LUA_SIGNATURE[0]) - S.name = "binary string"; - else - S.name = name; - S.L = L; - S.Z = Z; - checkHeader(&S); - cl = luaF_newLclosure(L, LoadByte(&S)); - setclLvalue(L, L->top, cl); - luaD_inctop(L); - cl->p = luaF_newproto(L); - LoadFunction(&S, cl->p, NULL); - lua_assert(cl->nupvalues == cl->p->sizeupvalues); - luai_verifycode(L, buff, cl->p); - return cl; -} - +/* +** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +#define lundump_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstring.h" +#include "lundump.h" +#include "lzio.h" + + +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + + +typedef struct { + lua_State *L; + ZIO *Z; + const char *name; +} LoadState; + + +static l_noret error(LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); +} + + +/* +** All high-level loads go through LoadVector; you can change it to +** adapt to the endianness of the input +*/ +#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) + +static void LoadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated"); +} + + +#define LoadVar(S,x) LoadVector(S,&x,1) + + +static lu_byte LoadByte (LoadState *S) { + lu_byte x; + LoadVar(S, x); + return x; +} + + +static int LoadInt (LoadState *S) { + int x; + LoadVar(S, x); + return x; +} + + +static lua_Number LoadNumber (LoadState *S) { + lua_Number x; + LoadVar(S, x); + return x; +} + + +static lua_Integer LoadInteger (LoadState *S) { + lua_Integer x; + LoadVar(S, x); + return x; +} + + +static TString *LoadString (LoadState *S) { + size_t size = LoadByte(S); + if (size == 0xFF) + LoadVar(S, size); + if (size == 0) + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + LoadVector(S, buff, size); + return luaS_newlstr(S->L, buff, size); + } + else { /* long string */ + TString *ts = luaS_createlngstrobj(S->L, size); + LoadVector(S, getstr(ts), size); /* load directly in final place */ + return ts; + } +} + + +static void LoadCode (LoadState *S, Proto *f) { + int n = LoadInt(S); + f->code = luaM_newvector(S->L, n, Instruction); + f->sizecode = n; + LoadVector(S, f->code, n); +} + + +static void LoadFunction(LoadState *S, Proto *f, TString *psource); + + +static void LoadConstants (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->k = luaM_newvector(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = LoadByte(S); + switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S)); + break; + default: + lua_assert(0); + } + } +} + + +static void LoadProtos (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->p = luaM_newvector(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L); + LoadFunction(S, f->p[i], f->source); + } +} + + +static void LoadUpvalues (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { + f->upvalues[i].instack = LoadByte(S); + f->upvalues[i].idx = LoadByte(S); + } +} + + +static void LoadDebug (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->lineinfo = luaM_newvector(S->L, n, int); + f->sizelineinfo = n; + LoadVector(S, f->lineinfo, n); + n = LoadInt(S); + f->locvars = luaM_newvector(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = LoadString(S); + f->locvars[i].startpc = LoadInt(S); + f->locvars[i].endpc = LoadInt(S); + } + n = LoadInt(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = LoadString(S); +} + + +static void LoadFunction (LoadState *S, Proto *f, TString *psource) { + f->source = LoadString(S); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = LoadInt(S); + f->lastlinedefined = LoadInt(S); + f->numparams = LoadByte(S); + f->is_vararg = LoadByte(S); + f->maxstacksize = LoadByte(S); + LoadCode(S, f); + LoadConstants(S, f); + LoadUpvalues(S, f); + LoadProtos(S, f); + LoadDebug(S, f); +} + + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + LoadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); +} + + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (LoadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ + if (LoadByte(S) != LUAC_VERSION) + error(S, "version mismatch in"); + if (LoadByte(S) != LUAC_FORMAT) + error(S, "format mismatch in"); + checkliteral(S, LUAC_DATA, "corrupted"); + checksize(S, int); + checksize(S, size_t); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (LoadInteger(S) != LUAC_INT) + error(S, "endianness mismatch in"); + if (LoadNumber(S) != LUAC_NUM) + error(S, "float format mismatch in"); +} + + +/* +** load precompiled chunk +*/ +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, LoadByte(&S)); + setclLvalue(L, L->top, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + LoadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, buff, cl->p); + return cl; +} + diff --git a/libs/lua/source/lutf8lib.c b/libs/lua/source/lutf8lib.c index 10bd238a..e836b941 100644 --- a/libs/lua/source/lutf8lib.c +++ b/libs/lua/source/lutf8lib.c @@ -1,256 +1,256 @@ -/* -** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard library for UTF-8 manipulation -** See Copyright Notice in lua.h -*/ - -#define lutf8lib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - -#define MAXUNICODE 0x10FFFF - -#define iscont(p) ((*(p) & 0xC0) == 0x80) - - -/* from strlib */ -/* translate a relative string position: negative means back from end */ -static lua_Integer u_posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -/* -** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. -*/ -static const char *utf8_decode (const char *o, int *val) { - static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; - const unsigned char *s = (const unsigned char *)o; - unsigned int c = s[0]; - unsigned int res = 0; /* final result */ - if (c < 0x80) /* ascii? */ - res = c; - else { - int count = 0; /* to count number of continuation bytes */ - while (c & 0x40) { /* still have continuation bytes? */ - int cc = s[++count]; /* read next byte */ - if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ - return NULL; /* invalid byte sequence */ - res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ - c <<= 1; /* to test next bit */ - } - res |= ((c & 0x7F) << (count * 5)); /* add first byte */ - if (count > 3 || res > MAXUNICODE || res <= limits[count]) - return NULL; /* invalid byte sequence */ - s += count; /* skip continuation bytes read */ - } - if (val) *val = res; - return (const char *)s + 1; /* +1 to include first byte */ -} - - -/* -** utf8len(s [, i [, j]]) --> number of characters that start in the -** range [i,j], or nil + current position if 's' is not well formed in -** that interval -*/ -static int utflen (lua_State *L) { - int n = 0; - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, - "initial position out of string"); - luaL_argcheck(L, --posj < (lua_Integer)len, 3, - "final position out of string"); - while (posi <= posj) { - const char *s1 = utf8_decode(s + posi, NULL); - if (s1 == NULL) { /* conversion error? */ - lua_pushnil(L); /* return nil ... */ - lua_pushinteger(L, posi + 1); /* ... and current position */ - return 2; - } - posi = s1 - s; - n++; - } - lua_pushinteger(L, n); - return 1; -} - - -/* -** codepoint(s, [i, [j]]) -> returns codepoints for all characters -** that start in the range [i,j] -*/ -static int codepoint (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); - int n; - const char *se; - luaL_argcheck(L, posi >= 1, 2, "out of range"); - luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - n = 0; - se = s + pose; - for (s += posi - 1; s < se;) { - int code; - s = utf8_decode(s, &code); - if (s == NULL) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, code); - n++; - } - return n; -} - - -static void pushutfchar (lua_State *L, int arg) { - lua_Integer code = luaL_checkinteger(L, arg); - luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); - lua_pushfstring(L, "%U", (long)code); -} - - -/* -** utfchar(n1, n2, ...) -> char(n1)..char(n2)... -*/ -static int utfchar (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - if (n == 1) /* optimize common case of single char */ - pushutfchar(L, 1); - else { - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for (i = 1; i <= n; i++) { - pushutfchar(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - } - return 1; -} - - -/* -** offset(s, n, [i]) -> index where n-th character counting from -** position 'i' starts; 0 means character at 'i'. -*/ -static int byteoffset (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = luaL_checkinteger(L, 2); - lua_Integer posi = (n >= 0) ? 1 : len + 1; - posi = u_posrelat(luaL_optinteger(L, 3, posi), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, - "position out of range"); - if (n == 0) { - /* find beginning of current byte sequence */ - while (posi > 0 && iscont(s + posi)) posi--; - } - else { - if (iscont(s + posi)) - return luaL_error(L, "initial position is a continuation byte"); - if (n < 0) { - while (n < 0 && posi > 0) { /* move back */ - do { /* find beginning of previous character */ - posi--; - } while (posi > 0 && iscont(s + posi)); - n++; - } - } - else { - n--; /* do not move for 1st character */ - while (n > 0 && posi < (lua_Integer)len) { - do { /* find beginning of next character */ - posi++; - } while (iscont(s + posi)); /* (cannot pass final '\0') */ - n--; - } - } - } - if (n == 0) /* did it find given character? */ - lua_pushinteger(L, posi + 1); - else /* no such character */ - lua_pushnil(L); - return 1; -} - - -static int iter_aux (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ - } - if (n >= (lua_Integer)len) - return 0; /* no more codepoints */ - else { - int code; - const char *next = utf8_decode(s + n, &code); - if (next == NULL || iscont(next)) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, n + 1); - lua_pushinteger(L, code); - return 2; - } -} - - -static int iter_codes (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcfunction(L, iter_aux); - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - return 3; -} - - -/* pattern to match a single UTF-8 character */ -#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" - - -static const luaL_Reg funcs[] = { - {"offset", byteoffset}, - {"codepoint", codepoint}, - {"char", utfchar}, - {"len", utflen}, - {"codes", iter_codes}, - /* placeholders */ - {"charpattern", NULL}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_utf8 (lua_State *L) { - luaL_newlib(L, funcs); - lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); - lua_setfield(L, -2, "charpattern"); - return 1; -} - +/* +** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#define MAXUNICODE 0x10FFFF + +#define iscont(p) ((*(p) & 0xC0) == 0x80) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +*/ +static const char *utf8_decode (const char *o, int *val) { + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char *s = (const unsigned char *)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) { /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char *)s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j]]) --> number of characters that start in the +** range [i,j], or nil + current position if 's' is not well formed in +** that interval +*/ +static int utflen (lua_State *L) { + int n = 0; + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) { /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j]]) -> returns codepoints for all characters +** that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else { + if (iscont(s + posi)) + return luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscont(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; +} + + +static int iter_aux (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else { + int code; + const char *next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_codes (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/libs/lua/source/lvm.c b/libs/lua/source/lvm.c index cc43d871..b89d8342 100644 --- a/libs/lua/source/lvm.c +++ b/libs/lua/source/lvm.c @@ -1,1322 +1,1322 @@ -/* -** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - -#define lvm_c -#define LUA_CORE - -#include "lprefix.h" - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - -/* limit for table tag-method chains (to avoid loops) */ -#define MAXTAGLOOP 2000 - - - -/* -** 'l_intfitsf' checks whether a given integer can be converted to a -** float without rounding. Used in comparisons. Left undefined if -** all integers fit in a float precisely. -*/ -#if !defined(l_intfitsf) - -/* number of bits in the mantissa of a float */ -#define NBM (l_mathlim(MANT_DIG)) - -/* -** Check whether some integers may not fit in a float, that is, whether -** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). -** (The shifts are done in parts to avoid shifting by more than the size -** of an integer. In a worst case, NBM == 113 for long double and -** sizeof(integer) == 32.) -*/ -#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ - >> (NBM - (3 * (NBM / 4)))) > 0 - -#define l_intfitsf(i) \ - (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) - -#endif - -#endif - - - -/* -** Try to convert a value to a float. The float case is already handled -** by the macro 'tonumber'. -*/ -int luaV_tonumber_ (const TValue *obj, lua_Number *n) { - TValue v; - if (ttisinteger(obj)) { - *n = cast_num(ivalue(obj)); - return 1; - } - else if (cvt2num(obj) && /* string convertible to number? */ - luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { - *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ - return 1; - } - else - return 0; /* conversion failed */ -} - - -/* -** try to convert a value to an integer, rounding according to 'mode': -** mode == 0: accepts only integral values -** mode == 1: takes the floor of the number -** mode == 2: takes the ceil of the number -*/ -int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { - TValue v; - again: - if (ttisfloat(obj)) { - lua_Number n = fltvalue(obj); - lua_Number f = l_floor(n); - if (n != f) { /* not an integral value? */ - if (mode == 0) return 0; /* fails if mode demands integral value */ - else if (mode > 1) /* needs ceil? */ - f += 1; /* convert floor to ceil (remember: n != f) */ - } - return lua_numbertointeger(f, p); - } - else if (ttisinteger(obj)) { - *p = ivalue(obj); - return 1; - } - else if (cvt2num(obj) && - luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { - obj = &v; - goto again; /* convert result from 'luaO_str2num' to an integer */ - } - return 0; /* conversion failed */ -} - - -/* -** Try to convert a 'for' limit to an integer, preserving the -** semantics of the loop. -** (The following explanation assumes a non-negative step; it is valid -** for negative steps mutatis mutandis.) -** If the limit can be converted to an integer, rounding down, that is -** it. -** Otherwise, check whether the limit can be converted to a number. If -** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, -** which means no limit. If the number is too negative, the loop -** should not run, because any initial integer value is larger than the -** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects -** the extreme case when the initial value is LUA_MININTEGER, in which -** case the LUA_MININTEGER limit would still run the loop once. -*/ -static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, - int *stopnow) { - *stopnow = 0; /* usually, let loops run */ - if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ - lua_Number n; /* try to convert to float */ - if (!tonumber(obj, &n)) /* cannot convert to float? */ - return 0; /* not a number */ - if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ - *p = LUA_MAXINTEGER; - if (step < 0) *stopnow = 1; - } - else { /* float is smaller than min integer */ - *p = LUA_MININTEGER; - if (step >= 0) *stopnow = 1; - } - } - return 1; -} - - -/* -** Finish the table access 'val = t[key]'. -** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to -** t[k] entry (which must be nil). -*/ -void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, - const TValue *slot) { - int loop; /* counter to avoid infinite loops */ - const TValue *tm; /* metamethod */ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - if (slot == NULL) { /* 't' is not a table? */ - lua_assert(!ttistable(t)); - tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); /* no metamethod */ - /* else will try the metamethod */ - } - else { /* 't' is a table */ - lua_assert(ttisnil(slot)); - tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ - if (tm == NULL) { /* no metamethod? */ - setnilvalue(val); /* result is nil */ - return; - } - /* else will try the metamethod */ - } - if (ttisfunction(tm)) { /* is metamethod a function? */ - luaT_callTM(L, tm, t, key, val, 1); /* call it */ - return; - } - t = tm; /* else try to access 'tm[key]' */ - if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ - setobj2s(L, val, slot); /* done */ - return; - } - /* else repeat (tail call 'luaV_finishget') */ - } - luaG_runerror(L, "'__index' chain too long; possible loop"); -} - - -/* -** Finish a table assignment 't[key] = val'. -** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points -** to the entry 't[key]', or to 'luaO_nilobject' if there is no such -** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' -** would have done the job.) -*/ -void luaV_finishset (lua_State *L, const TValue *t, TValue *key, - StkId val, const TValue *slot) { - int loop; /* counter to avoid infinite loops */ - for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; /* '__newindex' metamethod */ - if (slot != NULL) { /* is 't' a table? */ - Table *h = hvalue(t); /* save 't' table */ - lua_assert(ttisnil(slot)); /* old value must be nil */ - tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ - if (tm == NULL) { /* no metamethod? */ - if (slot == luaO_nilobject) /* no previous entry? */ - slot = luaH_newkey(L, h, key); /* create one */ - /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, cast(TValue *, slot), val); /* set its new value */ - invalidateTMcache(h); - luaC_barrierback(L, h, val); - return; - } - /* else will try the metamethod */ - } - else { /* not a table; check metamethod */ - if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); - } - /* try the metamethod */ - if (ttisfunction(tm)) { - luaT_callTM(L, tm, t, key, val, 0); - return; - } - t = tm; /* else repeat assignment over 'tm' */ - if (luaV_fastset(L, t, key, slot, luaH_get, val)) - return; /* done */ - /* else loop */ - } - luaG_runerror(L, "'__newindex' chain too long; possible loop"); -} - - -/* -** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- -** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. -** The code is a little tricky because it allows '\0' in the strings -** and it uses 'strcoll' (to respect locales) for each segments -** of the strings. -*/ -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = tsslen(ls); - const char *r = getstr(rs); - size_t lr = tsslen(rs); - for (;;) { /* for each segment */ - int temp = strcoll(l, r); - if (temp != 0) /* not equal? */ - return temp; /* done */ - else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == lr) /* 'rs' is finished? */ - return (len == ll) ? 0 : 1; /* check 'ls' */ - else if (len == ll) /* 'ls' is finished? */ - return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ - /* both strings longer than 'len'; go on comparing after the '\0' */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } -} - - -/* -** Check whether integer 'i' is less than float 'f'. If 'i' has an -** exact representation as a float ('l_intfitsf'), compare numbers as -** floats. Otherwise, if 'f' is outside the range for integers, result -** is trivial. Otherwise, compare them as integers. (When 'i' has no -** float representation, either 'f' is "far away" from 'i' or 'f' has -** no precision left for a fractional part; either way, how 'f' is -** truncated is irrelevant.) When 'f' is NaN, comparisons must result -** in false. -*/ -static int LTintfloat (lua_Integer i, lua_Number f) { -#if defined(l_intfitsf) - if (!l_intfitsf(i)) { - if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ - return 1; /* f >= maxint + 1 > i */ - else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ - return (i < cast(lua_Integer, f)); /* compare them as integers */ - else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ - return 0; - } -#endif - return luai_numlt(cast_num(i), f); /* compare them as floats */ -} - - -/* -** Check whether integer 'i' is less than or equal to float 'f'. -** See comments on previous function. -*/ -static int LEintfloat (lua_Integer i, lua_Number f) { -#if defined(l_intfitsf) - if (!l_intfitsf(i)) { - if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ - return 1; /* f >= maxint + 1 > i */ - else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ - return (i <= cast(lua_Integer, f)); /* compare them as integers */ - else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ - return 0; - } -#endif - return luai_numle(cast_num(i), f); /* compare them as floats */ -} - - -/* -** Return 'l < r', for numbers. -*/ -static int LTnum (const TValue *l, const TValue *r) { - if (ttisinteger(l)) { - lua_Integer li = ivalue(l); - if (ttisinteger(r)) - return li < ivalue(r); /* both are integers */ - else /* 'l' is int and 'r' is float */ - return LTintfloat(li, fltvalue(r)); /* l < r ? */ - } - else { - lua_Number lf = fltvalue(l); /* 'l' must be float */ - if (ttisfloat(r)) - return luai_numlt(lf, fltvalue(r)); /* both are float */ - else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ - return 0; /* NaN < i is always false */ - else /* without NaN, (l < r) <--> not(r <= l) */ - return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ - } -} - - -/* -** Return 'l <= r', for numbers. -*/ -static int LEnum (const TValue *l, const TValue *r) { - if (ttisinteger(l)) { - lua_Integer li = ivalue(l); - if (ttisinteger(r)) - return li <= ivalue(r); /* both are integers */ - else /* 'l' is int and 'r' is float */ - return LEintfloat(li, fltvalue(r)); /* l <= r ? */ - } - else { - lua_Number lf = fltvalue(l); /* 'l' must be float */ - if (ttisfloat(r)) - return luai_numle(lf, fltvalue(r)); /* both are float */ - else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ - return 0; /* NaN <= i is always false */ - else /* without NaN, (l <= r) <--> not(r < l) */ - return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ - } -} - - -/* -** Main operation less than; return 'l < r'. -*/ -int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { - int res; - if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ - return LTnum(l, r); - else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ - return l_strcmp(tsvalue(l), tsvalue(r)) < 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ - luaG_ordererror(L, l, r); /* error */ - return res; -} - - -/* -** Main operation less than or equal to; return 'l <= r'. If it needs -** a metamethod and there is no '__le', try '__lt', based on -** l <= r iff !(r < l) (assuming a total order). If the metamethod -** yields during this substitution, the continuation has to know -** about it (to negate the result of r= 0) /* try 'le' */ - return res; - else { /* try 'lt': */ - L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ - res = luaT_callorderTM(L, r, l, TM_LT); - L->ci->callstatus ^= CIST_LEQ; /* clear mark */ - if (res < 0) - luaG_ordererror(L, l, r); - return !res; /* result is negated */ - } -} - - -/* -** Main operation for equality of Lua values; return 't1 == t2'. -** L == NULL means raw equality (no metamethods) -*/ -int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { - const TValue *tm; - if (ttype(t1) != ttype(t2)) { /* not the same variant? */ - if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) - return 0; /* only numbers can be equal with different variants */ - else { /* two numbers with different variants */ - lua_Integer i1, i2; /* compare them as integers */ - return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); - } - } - /* values have same type and same variant */ - switch (ttype(t1)) { - case LUA_TNIL: return 1; - case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); - case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); - case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ - case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); - case LUA_TLCF: return fvalue(t1) == fvalue(t2); - case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); - case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); - case LUA_TUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - case LUA_TTABLE: { - if (hvalue(t1) == hvalue(t2)) return 1; - else if (L == NULL) return 0; - tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); - if (tm == NULL) - tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - default: - return gcvalue(t1) == gcvalue(t2); - } - if (tm == NULL) /* no TM? */ - return 0; /* objects are different */ - luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ - return !l_isfalse(L->top); -} - - -/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ -#define tostring(L,o) \ - (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) - -#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) - -/* copy strings in stack from top - n up to top - 1 to buffer */ -static void copy2buff (StkId top, int n, char *buff) { - size_t tl = 0; /* size already copied */ - do { - size_t l = vslen(top - n); /* length of string being copied */ - memcpy(buff + tl, svalue(top - n), l * sizeof(char)); - tl += l; - } while (--n > 0); -} - - -/* -** Main operation for concatenation: concat 'total' values in the stack, -** from 'L->top - total' up to 'L->top - 1'. -*/ -void luaV_concat (lua_State *L, int total) { - lua_assert(total >= 2); - do { - StkId top = L->top; - int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) - luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); - else if (isemptystr(top - 1)) /* second operand is empty? */ - cast_void(tostring(L, top - 2)); /* result is first operand */ - else if (isemptystr(top - 2)) { /* first operand is an empty string? */ - setobjs2s(L, top - 2, top - 1); /* result is second op. */ - } - else { - /* at least two non-empty string values; get as many as possible */ - size_t tl = vslen(top - 1); - TString *ts; - /* collect total length and number of strings */ - for (n = 1; n < total && tostring(L, top - n - 1); n++) { - size_t l = vslen(top - n - 1); - if (l >= (MAX_SIZE/sizeof(char)) - tl) - luaG_runerror(L, "string length overflow"); - tl += l; - } - if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ - char buff[LUAI_MAXSHORTLEN]; - copy2buff(top, n, buff); /* copy strings to buffer */ - ts = luaS_newlstr(L, buff, tl); - } - else { /* long string; copy strings directly to final result */ - ts = luaS_createlngstrobj(L, tl); - copy2buff(top, n, getstr(ts)); - } - setsvalue2s(L, top - n, ts); /* create result */ - } - total -= n-1; /* got 'n' strings to create 1 new */ - L->top -= n-1; /* popped 'n' strings and pushed one */ - } while (total > 1); /* repeat until only 1 result left */ -} - - -/* -** Main operation 'ra' = #rb'. -*/ -void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { - const TValue *tm; - switch (ttype(rb)) { - case LUA_TTABLE: { - Table *h = hvalue(rb); - tm = fasttm(L, h->metatable, TM_LEN); - if (tm) break; /* metamethod? break switch to call it */ - setivalue(ra, luaH_getn(h)); /* else primitive len */ - return; - } - case LUA_TSHRSTR: { - setivalue(ra, tsvalue(rb)->shrlen); - return; - } - case LUA_TLNGSTR: { - setivalue(ra, tsvalue(rb)->u.lnglen); - return; - } - default: { /* try metamethod */ - tm = luaT_gettmbyobj(L, rb, TM_LEN); - if (ttisnil(tm)) /* no metamethod? */ - luaG_typeerror(L, rb, "get length of"); - break; - } - } - luaT_callTM(L, tm, rb, rb, ra, 1); -} - - -/* -** Integer division; return 'm // n', that is, floor(m/n). -** C division truncates its result (rounds towards zero). -** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, -** otherwise 'floor(q) == trunc(q) - 1'. -*/ -lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to divide by zero"); - return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ - } - else { - lua_Integer q = m / n; /* perform C division */ - if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ - q -= 1; /* correct result for different rounding */ - return q; - } -} - - -/* -** Integer modulus; return 'm % n'. (Assume that C '%' with -** negative operands follows C99 behavior. See previous comment -** about luaV_div.) -*/ -lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { - if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) - luaG_runerror(L, "attempt to perform 'n%%0'"); - return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ - } - else { - lua_Integer r = m % n; - if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ - r += n; /* correct result for different rounding */ - return r; - } -} - - -/* number of bits in an integer */ -#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) - -/* -** Shift left operation. (Shift right just negates 'y'.) -*/ -lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { - if (y < 0) { /* shift right? */ - if (y <= -NBITS) return 0; - else return intop(>>, x, -y); - } - else { /* shift left */ - if (y >= NBITS) return 0; - else return intop(<<, x, y); - } -} - - -/* -** check whether cached closure in prototype 'p' may be reused, that is, -** whether there is a cached closure with the same upvalues needed by -** new closure to be created. -*/ -static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { - LClosure *c = p->cache; - if (c != NULL) { /* is there a cached closure? */ - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; - int i; - for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ - TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; - if (c->upvals[i]->v != v) - return NULL; /* wrong upvalue; cannot reuse closure */ - } - } - return c; /* return cached closure (or NULL if no cached closure) */ -} - - -/* -** create a new Lua closure, push it in the stack, and initialize -** its upvalues. Note that the closure is not cached if prototype is -** already black (which means that 'cache' was already cleared by the -** GC). -*/ -static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, - StkId ra) { - int nup = p->sizeupvalues; - Upvaldesc *uv = p->upvalues; - int i; - LClosure *ncl = luaF_newLclosure(L, nup); - ncl->p = p; - setclLvalue(L, ra, ncl); /* anchor new closure in stack */ - for (i = 0; i < nup; i++) { /* fill in its upvalues */ - if (uv[i].instack) /* upvalue refers to local variable? */ - ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); - else /* get upvalue from enclosing function */ - ncl->upvals[i] = encup[uv[i].idx]; - ncl->upvals[i]->refcount++; - /* new closure is white, so we do not need a barrier here */ - } - if (!isblack(p)) /* cache will not break GC invariant? */ - p->cache = ncl; /* save it on cache for reuse */ -} - - -/* -** finish execution of an opcode interrupted by an yield -*/ -void luaV_finishOp (lua_State *L) { - CallInfo *ci = L->ci; - StkId base = ci->u.l.base; - Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ - OpCode op = GET_OPCODE(inst); - switch (op) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: - case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: - case OP_MOD: case OP_POW: - case OP_UNM: case OP_BNOT: case OP_LEN: - case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { - setobjs2s(L, base + GETARG_A(inst), --L->top); - break; - } - case OP_LE: case OP_LT: case OP_EQ: { - int res = !l_isfalse(L->top - 1); - L->top--; - if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ - lua_assert(op == OP_LE); - ci->callstatus ^= CIST_LEQ; /* clear mark */ - res = !res; /* negate result */ - } - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); - if (res != GETARG_A(inst)) /* condition failed? */ - ci->u.l.savedpc++; /* skip jump instruction */ - break; - } - case OP_CONCAT: { - StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ - int b = GETARG_B(inst); /* first element to concatenate */ - int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ - setobj2s(L, top - 2, top); /* put TM result in proper position */ - if (total > 1) { /* are there elements to concat? */ - L->top = top - 1; /* top is one after last element (at top-2) */ - luaV_concat(L, total); /* concat them (may yield again) */ - } - /* move final result to final position */ - setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); - L->top = ci->top; /* restore top */ - break; - } - case OP_TFORCALL: { - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); - L->top = ci->top; /* correct top */ - break; - } - case OP_CALL: { - if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ - L->top = ci->top; /* adjust results */ - break; - } - case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: - break; - default: lua_assert(0); - } -} - - - - -/* -** {================================================================== -** Function 'luaV_execute': main interpreter loop -** =================================================================== -*/ - - -/* -** some macros for common tasks in 'luaV_execute' -*/ - - -#define RA(i) (base+GETARG_A(i)) -#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) -#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) -#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ - ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) -#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ - ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) - - -/* execute a jump instruction */ -#define dojump(ci,i,e) \ - { int a = GETARG_A(i); \ - if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ - ci->u.l.savedpc += GETARG_sBx(i) + e; } - -/* for test instructions, execute the jump instruction that follows it */ -#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); } - - -#define Protect(x) { {x;}; base = ci->u.l.base; } - -#define checkGC(L,c) \ - { luaC_condGC(L, L->top = (c), /* limit of live values */ \ - Protect(L->top = ci->top)); /* restore top */ \ - luai_threadyield(L); } - - -/* fetch an instruction and prepare its execution */ -#define vmfetch() { \ - i = *(ci->u.l.savedpc++); \ - if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \ - Protect(luaG_traceexec(L)); \ - ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \ - lua_assert(base == ci->u.l.base); \ - lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \ -} - -#define vmdispatch(o) switch(o) -#define vmcase(l) case l: -#define vmbreak break - - -/* -** copy of 'luaV_gettable', but protecting the call to potential -** metamethod (which can reallocate the stack) -*/ -#define gettableProtected(L,t,k,v) { const TValue *slot; \ - if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ - else Protect(luaV_finishget(L,t,k,v,slot)); } - - -/* same for 'luaV_settable' */ -#define settableProtected(L,t,k,v) { const TValue *slot; \ - if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ - Protect(luaV_finishset(L,t,k,v,slot)); } - - - -void luaV_execute (lua_State *L) { - CallInfo *ci = L->ci; - LClosure *cl; - TValue *k; - StkId base; - ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ - newframe: /* reentry point when frame changes (call/return) */ - lua_assert(ci == L->ci); - cl = clLvalue(ci->func); /* local reference to function's closure */ - k = cl->p->k; /* local reference to function's constant table */ - base = ci->u.l.base; /* local copy of function's base */ - /* main loop of interpreter */ - for (;;) { - Instruction i; - StkId ra; - vmfetch(); - vmdispatch (GET_OPCODE(i)) { - vmcase(OP_MOVE) { - setobjs2s(L, ra, RB(i)); - vmbreak; - } - vmcase(OP_LOADK) { - TValue *rb = k + GETARG_Bx(i); - setobj2s(L, ra, rb); - vmbreak; - } - vmcase(OP_LOADKX) { - TValue *rb; - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); - rb = k + GETARG_Ax(*ci->u.l.savedpc++); - setobj2s(L, ra, rb); - vmbreak; - } - vmcase(OP_LOADBOOL) { - setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - vmbreak; - } - vmcase(OP_LOADNIL) { - int b = GETARG_B(i); - do { - setnilvalue(ra++); - } while (b--); - vmbreak; - } - vmcase(OP_GETUPVAL) { - int b = GETARG_B(i); - setobj2s(L, ra, cl->upvals[b]->v); - vmbreak; - } - vmcase(OP_GETTABUP) { - TValue *upval = cl->upvals[GETARG_B(i)]->v; - TValue *rc = RKC(i); - gettableProtected(L, upval, rc, ra); - vmbreak; - } - vmcase(OP_GETTABLE) { - StkId rb = RB(i); - TValue *rc = RKC(i); - gettableProtected(L, rb, rc, ra); - vmbreak; - } - vmcase(OP_SETTABUP) { - TValue *upval = cl->upvals[GETARG_A(i)]->v; - TValue *rb = RKB(i); - TValue *rc = RKC(i); - settableProtected(L, upval, rb, rc); - vmbreak; - } - vmcase(OP_SETUPVAL) { - UpVal *uv = cl->upvals[GETARG_B(i)]; - setobj(L, uv->v, ra); - luaC_upvalbarrier(L, uv); - vmbreak; - } - vmcase(OP_SETTABLE) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - settableProtected(L, ra, rb, rc); - vmbreak; - } - vmcase(OP_NEWTABLE) { - int b = GETARG_B(i); - int c = GETARG_C(i); - Table *t = luaH_new(L); - sethvalue(L, ra, t); - if (b != 0 || c != 0) - luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - checkGC(L, ra + 1); - vmbreak; - } - vmcase(OP_SELF) { - const TValue *aux; - StkId rb = RB(i); - TValue *rc = RKC(i); - TString *key = tsvalue(rc); /* key must be a string */ - setobjs2s(L, ra + 1, rb); - if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { - setobj2s(L, ra, aux); - } - else Protect(luaV_finishget(L, rb, rc, ra, aux)); - vmbreak; - } - vmcase(OP_ADD) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(+, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numadd(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } - vmbreak; - } - vmcase(OP_SUB) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(-, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numsub(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } - vmbreak; - } - vmcase(OP_MUL) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, intop(*, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_nummul(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } - vmbreak; - } - vmcase(OP_DIV) { /* float division (always with floats) */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numdiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } - vmbreak; - } - vmcase(OP_BAND) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(&, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } - vmbreak; - } - vmcase(OP_BOR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(|, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } - vmbreak; - } - vmcase(OP_BXOR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, intop(^, ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } - vmbreak; - } - vmcase(OP_SHL) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } - vmbreak; - } - vmcase(OP_SHR) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Integer ib; lua_Integer ic; - if (tointeger(rb, &ib) && tointeger(rc, &ic)) { - setivalue(ra, luaV_shiftl(ib, -ic)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } - vmbreak; - } - vmcase(OP_MOD) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_mod(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - lua_Number m; - luai_nummod(L, nb, nc, m); - setfltvalue(ra, m); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } - vmbreak; - } - vmcase(OP_IDIV) { /* floor division */ - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (ttisinteger(rb) && ttisinteger(rc)) { - lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(ra, luaV_div(L, ib, ic)); - } - else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numidiv(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } - vmbreak; - } - vmcase(OP_POW) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - lua_Number nb; lua_Number nc; - if (tonumber(rb, &nb) && tonumber(rc, &nc)) { - setfltvalue(ra, luai_numpow(L, nb, nc)); - } - else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } - vmbreak; - } - vmcase(OP_UNM) { - TValue *rb = RB(i); - lua_Number nb; - if (ttisinteger(rb)) { - lua_Integer ib = ivalue(rb); - setivalue(ra, intop(-, 0, ib)); - } - else if (tonumber(rb, &nb)) { - setfltvalue(ra, luai_numunm(L, nb)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); - } - vmbreak; - } - vmcase(OP_BNOT) { - TValue *rb = RB(i); - lua_Integer ib; - if (tointeger(rb, &ib)) { - setivalue(ra, intop(^, ~l_castS2U(0), ib)); - } - else { - Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); - } - vmbreak; - } - vmcase(OP_NOT) { - TValue *rb = RB(i); - int res = l_isfalse(rb); /* next assignment may change this value */ - setbvalue(ra, res); - vmbreak; - } - vmcase(OP_LEN) { - Protect(luaV_objlen(L, ra, RB(i))); - vmbreak; - } - vmcase(OP_CONCAT) { - int b = GETARG_B(i); - int c = GETARG_C(i); - StkId rb; - L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c - b + 1)); - ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ - rb = base + b; - setobjs2s(L, ra, rb); - checkGC(L, (ra >= rb ? ra + 1 : rb)); - L->top = ci->top; /* restore top */ - vmbreak; - } - vmcase(OP_JMP) { - dojump(ci, i, 0); - vmbreak; - } - vmcase(OP_EQ) { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - Protect( - if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_LT) { - Protect( - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_LE) { - Protect( - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) - ci->u.l.savedpc++; - else - donextjump(ci); - ) - vmbreak; - } - vmcase(OP_TEST) { - if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) - ci->u.l.savedpc++; - else - donextjump(ci); - vmbreak; - } - vmcase(OP_TESTSET) { - TValue *rb = RB(i); - if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) - ci->u.l.savedpc++; - else { - setobjs2s(L, ra, rb); - donextjump(ci); - } - vmbreak; - } - vmcase(OP_CALL) { - int b = GETARG_B(i); - int nresults = GETARG_C(i) - 1; - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - if (luaD_precall(L, ra, nresults)) { /* C function? */ - if (nresults >= 0) - L->top = ci->top; /* adjust results */ - Protect((void)0); /* update 'base' */ - } - else { /* Lua function */ - ci = L->ci; - goto newframe; /* restart luaV_execute over new Lua function */ - } - vmbreak; - } - vmcase(OP_TAILCALL) { - int b = GETARG_B(i); - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ - Protect((void)0); /* update 'base' */ - } - else { - /* tail call: put called frame (n) in place of caller one (o) */ - CallInfo *nci = L->ci; /* called frame */ - CallInfo *oci = nci->previous; /* caller frame */ - StkId nfunc = nci->func; /* called function */ - StkId ofunc = oci->func; /* caller function */ - /* last stack slot filled by 'precall' */ - StkId lim = nci->u.l.base + getproto(nfunc)->numparams; - int aux; - /* close all upvalues from previous call */ - if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); - /* move new frame into old one */ - for (aux = 0; nfunc + aux < lim; aux++) - setobjs2s(L, ofunc + aux, nfunc + aux); - oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ - oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ - oci->u.l.savedpc = nci->u.l.savedpc; - oci->callstatus |= CIST_TAIL; /* function was tail called */ - ci = L->ci = oci; /* remove new frame */ - lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); - goto newframe; /* restart luaV_execute over new Lua function */ - } - vmbreak; - } - vmcase(OP_RETURN) { - int b = GETARG_B(i); - if (cl->p->sizep > 0) luaF_close(L, base); - b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); - if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ - return; /* external invocation: return */ - else { /* invocation via reentry: continue execution */ - ci = L->ci; - if (b) L->top = ci->top; - lua_assert(isLua(ci)); - lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - goto newframe; /* restart luaV_execute over new Lua function */ - } - } - vmcase(OP_FORLOOP) { - if (ttisinteger(ra)) { /* integer loop? */ - lua_Integer step = ivalue(ra + 2); - lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ - lua_Integer limit = ivalue(ra + 1); - if ((0 < step) ? (idx <= limit) : (limit <= idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - chgivalue(ra, idx); /* update internal index... */ - setivalue(ra + 3, idx); /* ...and external index */ - } - } - else { /* floating loop */ - lua_Number step = fltvalue(ra + 2); - lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ - lua_Number limit = fltvalue(ra + 1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - chgfltvalue(ra, idx); /* update internal index... */ - setfltvalue(ra + 3, idx); /* ...and external index */ - } - } - vmbreak; - } - vmcase(OP_FORPREP) { - TValue *init = ra; - TValue *plimit = ra + 1; - TValue *pstep = ra + 2; - lua_Integer ilimit; - int stopnow; - if (ttisinteger(init) && ttisinteger(pstep) && - forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { - /* all values are integer */ - lua_Integer initv = (stopnow ? 0 : ivalue(init)); - setivalue(plimit, ilimit); - setivalue(init, intop(-, initv, ivalue(pstep))); - } - else { /* try making all values floats */ - lua_Number ninit; lua_Number nlimit; lua_Number nstep; - if (!tonumber(plimit, &nlimit)) - luaG_runerror(L, "'for' limit must be a number"); - setfltvalue(plimit, nlimit); - if (!tonumber(pstep, &nstep)) - luaG_runerror(L, "'for' step must be a number"); - setfltvalue(pstep, nstep); - if (!tonumber(init, &ninit)) - luaG_runerror(L, "'for' initial value must be a number"); - setfltvalue(init, luai_numsub(L, ninit, nstep)); - } - ci->u.l.savedpc += GETARG_sBx(i); - vmbreak; - } - vmcase(OP_TFORCALL) { - StkId cb = ra + 3; /* call base */ - setobjs2s(L, cb+2, ra+2); - setobjs2s(L, cb+1, ra+1); - setobjs2s(L, cb, ra); - L->top = cb + 3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = ci->top; - i = *(ci->u.l.savedpc++); /* go to next instruction */ - ra = RA(i); - lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - goto l_tforloop; - } - vmcase(OP_TFORLOOP) { - l_tforloop: - if (!ttisnil(ra + 1)) { /* continue loop? */ - setobjs2s(L, ra, ra + 1); /* save control variable */ - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - } - vmbreak; - } - vmcase(OP_SETLIST) { - int n = GETARG_B(i); - int c = GETARG_C(i); - unsigned int last; - Table *h; - if (n == 0) n = cast_int(L->top - ra) - 1; - if (c == 0) { - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); - c = GETARG_Ax(*ci->u.l.savedpc++); - } - h = hvalue(ra); - last = ((c-1)*LFIELDS_PER_FLUSH) + n; - if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* preallocate it at once */ - for (; n > 0; n--) { - TValue *val = ra+n; - luaH_setint(L, h, last--, val); - luaC_barrierback(L, h, val); - } - L->top = ci->top; /* correct top (in case of previous open call) */ - vmbreak; - } - vmcase(OP_CLOSURE) { - Proto *p = cl->p->p[GETARG_Bx(i)]; - LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ - if (ncl == NULL) /* no match? */ - pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ - else - setclLvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L, ra + 1); - vmbreak; - } - vmcase(OP_VARARG) { - int b = GETARG_B(i) - 1; /* required results */ - int j; - int n = cast_int(base - ci->func) - cl->p->numparams - 1; - if (n < 0) /* less arguments than parameters? */ - n = 0; /* no vararg arguments */ - if (b < 0) { /* B == 0? */ - b = n; /* get all var. arguments */ - Protect(luaD_checkstack(L, n)); - ra = RA(i); /* previous call may change the stack */ - L->top = ra + n; - } - for (j = 0; j < b && j < n; j++) - setobjs2s(L, ra + j, base - n + j); - for (; j < b; j++) /* complete required results with nil */ - setnilvalue(ra + j); - vmbreak; - } - vmcase(OP_EXTRAARG) { - lua_assert(0); - vmbreak; - } - } - } -} - -/* }================================================================== */ - +/* +** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lvm.h" + + +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 2000 + + + +/* +** 'l_intfitsf' checks whether a given integer can be converted to a +** float without rounding. Used in comparisons. Left undefined if +** all integers fit in a float precisely. +*/ +#if !defined(l_intfitsf) + +/* number of bits in the mantissa of a float */ +#define NBM (l_mathlim(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, that is, whether +** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). +** (The shifts are done in parts to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(integer) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +#define l_intfitsf(i) \ + (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) + +#endif + +#endif + + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (cvt2num(obj) && /* string convertible to number? */ + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ + return 1; + } + else + return 0; /* conversion failed */ +} + + +/* +** try to convert a value to an integer, rounding according to 'mode': +** mode == 0: accepts only integral values +** mode == 1: takes the floor of the number +** mode == 2: takes the ceil of the number +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { + TValue v; + again: + if (ttisfloat(obj)) { + lua_Number n = fltvalue(obj); + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == 0) return 0; /* fails if mode demands integral value */ + else if (mode > 1) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); + } + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; + } + else if (cvt2num(obj) && + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + obj = &v; + goto again; /* convert result from 'luaO_str2num' to an integer */ + } + return 0; /* conversion failed */ +} + + +/* +** Try to convert a 'for' limit to an integer, preserving the +** semantics of the loop. +** (The following explanation assumes a non-negative step; it is valid +** for negative steps mutatis mutandis.) +** If the limit can be converted to an integer, rounding down, that is +** it. +** Otherwise, check whether the limit can be converted to a number. If +** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, +** which means no limit. If the number is too negative, the loop +** should not run, because any initial integer value is larger than the +** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects +** the extreme case when the initial value is LUA_MININTEGER, in which +** case the LUA_MININTEGER limit would still run the loop once. +*/ +static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, + int *stopnow) { + *stopnow = 0; /* usually, let loops run */ + if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else { /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } + } + return 1; +} + + +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be nil). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(ttisnil(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(val); /* result is nil */ + return; + } + /* else will try the metamethod */ + } + if (ttisfunction(tm)) { /* is metamethod a function? */ + luaT_callTM(L, tm, t, key, val, 1); /* call it */ + return; + } + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ + return; + } + /* else repeat (tail call 'luaV_finishget') */ + } + luaG_runerror(L, "'__index' chain too long; possible loop"); +} + + +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to 'luaO_nilobject' if there is no such +** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' +** would have done the job.) +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(ttisnil(slot)); /* old value must be nil */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + if (slot == luaO_nilobject) /* no previous entry? */ + slot = luaH_newkey(L, h, key); /* create one */ + /* no metamethod and (now) there is an entry with given key */ + setobj2t(L, cast(TValue *, slot), val); /* set its new value */ + invalidateTMcache(h); + luaC_barrierback(L, h, val); + return; + } + /* else will try the metamethod */ + } + else { /* not a table; check metamethod */ + if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ + if (ttisfunction(tm)) { + luaT_callTM(L, tm, t, key, val, 0); + return; + } + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, slot, luaH_get, val)) + return; /* done */ + /* else loop */ + } + luaG_runerror(L, "'__newindex' chain too long; possible loop"); +} + + +/* +** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- +** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } +} + + +/* +** Check whether integer 'i' is less than float 'f'. If 'i' has an +** exact representation as a float ('l_intfitsf'), compare numbers as +** floats. Otherwise, if 'f' is outside the range for integers, result +** is trivial. Otherwise, compare them as integers. (When 'i' has no +** float representation, either 'f' is "far away" from 'i' or 'f' has +** no precision left for a fractional part; either way, how 'f' is +** truncated is irrelevant.) When 'f' is NaN, comparisons must result +** in false. +*/ +static int LTintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ + return (i < cast(lua_Integer, f)); /* compare them as integers */ + else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ + return 0; + } +#endif + return luai_numlt(cast_num(i), f); /* compare them as floats */ +} + + +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +static int LEintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ + return (i <= cast(lua_Integer, f)); /* compare them as integers */ + else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ + return 0; + } +#endif + return luai_numle(cast_num(i), f); /* compare them as floats */ +} + + +/* +** Return 'l < r', for numbers. +*/ +static int LTnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN < i is always false */ + else /* without NaN, (l < r) <--> not(r <= l) */ + return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ + } +} + + +/* +** Return 'l <= r', for numbers. +*/ +static int LEnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN <= i is always false */ + else /* without NaN, (l <= r) <--> not(r < l) */ + return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ + } +} + + +/* +** Main operation less than; return 'l < r'. +*/ +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { + int res; + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ + luaG_ordererror(L, l, r); /* error */ + return res; +} + + +/* +** Main operation less than or equal to; return 'l <= r'. If it needs +** a metamethod and there is no '__le', try '__lt', based on +** l <= r iff !(r < l) (assuming a total order). If the metamethod +** yields during this substitution, the continuation has to know +** about it (to negate the result of r= 0) /* try 'le' */ + return res; + else { /* try 'lt': */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + res = luaT_callorderTM(L, r, l, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (res < 0) + luaG_ordererror(L, l, r); + return !res; /* result is negated */ + } +} + + +/* +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) +*/ +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; + if (ttype(t1) != ttype(t2)) { /* not the same variant? */ + if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + lua_Integer i1, i2; /* compare them as integers */ + return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); + } + } + /* values have same type and same variant */ + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: + return gcvalue(t1) == gcvalue(t2); + } + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ + return !l_isfalse(L->top); +} + + +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(top - n); /* length of string being copied */ + memcpy(buff + tl, svalue(top - n), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top - total' up to 'L->top - 1'. +*/ +void luaV_concat (lua_State *L, int total) { + lua_assert(total >= 2); + do { + StkId top = L->top; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) + luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); + else if (isemptystr(top - 1)) /* second operand is empty? */ + cast_void(tostring(L, top - 2)); /* result is first operand */ + else if (isemptystr(top - 2)) { /* first operand is an empty string? */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ + } + else { + /* at least two non-empty string values; get as many as possible */ + size_t tl = vslen(top - 1); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, top - n - 1); n++) { + size_t l = vslen(top - n - 1); + if (l >= (MAX_SIZE/sizeof(char)) - tl) + luaG_runerror(L, "string length overflow"); + tl += l; + } + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ + } + total -= n-1; /* got 'n' strings to create 1 new */ + L->top -= n-1; /* popped 'n' strings and pushed one */ + } while (total > 1); /* repeat until only 1 result left */ +} + + +/* +** Main operation 'ra' = #rb'. +*/ +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttype(rb)) { + case LUA_TTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setivalue(ra, luaH_getn(h)); /* else primitive len */ + return; + } + case LUA_TSHRSTR: { + setivalue(ra, tsvalue(rb)->shrlen); + return; + } + case LUA_TLNGSTR: { + setivalue(ra, tsvalue(rb)->u.lnglen); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (ttisnil(tm)) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + luaT_callTM(L, tm, rb, rb, ra, 1); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_div.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } +} + + +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); + } +} + + +/* +** check whether cached closure in prototype 'p' may be reused, that is, +** whether there is a cached closure with the same upvalues needed by +** new closure to be created. +*/ +static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { + LClosure *c = p->cache; + if (c != NULL) { /* is there a cached closure? */ + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ + TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; + if (c->upvals[i]->v != v) + return NULL; /* wrong upvalue; cannot reuse closure */ + } + } + return c; /* return cached closure (or NULL if no cached closure) */ +} + + +/* +** create a new Lua closure, push it in the stack, and initialize +** its upvalues. Note that the closure is not cached if prototype is +** already black (which means that 'cache' was already cleared by the +** GC). +*/ +static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, + StkId ra) { + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; + setclLvalue(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) { /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->upvals[i] = encup[uv[i].idx]; + ncl->upvals[i]->refcount++; + /* new closure is white, so we do not need a barrier here */ + } + if (!isblack(p)) /* cache will not break GC invariant? */ + p->cache = ncl; /* save it on cache for reuse */ +} + + +/* +** finish execution of an opcode interrupted by an yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->u.l.base; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + switch (op) { /* finish its execution */ + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_MOD: case OP_POW: + case OP_UNM: case OP_BNOT: case OP_LEN: + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top); + break; + } + case OP_LE: case OP_LT: case OP_EQ: { + int res = !l_isfalse(L->top - 1); + L->top--; + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + lua_assert(op == OP_LE); + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_A(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ + int b = GETARG_B(inst); /* first element to concatenate */ + int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ + setobj2s(L, top - 2, top); /* put TM result in proper position */ + if (total > 1) { /* are there elements to concat? */ + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + } + /* move final result to final position */ + setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ + break; + } + case OP_TFORCALL: { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ + break; + } + case OP_CALL: { + if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ + L->top = ci->top; /* adjust results */ + break; + } + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + + + +/* +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== +*/ + + +/* +** some macros for common tasks in 'luaV_execute' +*/ + + +#define RA(i) (base+GETARG_A(i)) +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) + + +/* execute a jump instruction */ +#define dojump(ci,i,e) \ + { int a = GETARG_A(i); \ + if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ + ci->u.l.savedpc += GETARG_sBx(i) + e; } + +/* for test instructions, execute the jump instruction that follows it */ +#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); } + + +#define Protect(x) { {x;}; base = ci->u.l.base; } + +#define checkGC(L,c) \ + { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + Protect(L->top = ci->top)); /* restore top */ \ + luai_threadyield(L); } + + +/* fetch an instruction and prepare its execution */ +#define vmfetch() { \ + i = *(ci->u.l.savedpc++); \ + if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \ + Protect(luaG_traceexec(L)); \ + ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \ + lua_assert(base == ci->u.l.base); \ + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \ +} + +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break + + +/* +** copy of 'luaV_gettable', but protecting the call to potential +** metamethod (which can reallocate the stack) +*/ +#define gettableProtected(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else Protect(luaV_finishget(L,t,k,v,slot)); } + + +/* same for 'luaV_settable' */ +#define settableProtected(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + Protect(luaV_finishset(L,t,k,v,slot)); } + + + +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; + LClosure *cl; + TValue *k; + StkId base; + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ + newframe: /* reentry point when frame changes (call/return) */ + lua_assert(ci == L->ci); + cl = clLvalue(ci->func); /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = ci->u.l.base; /* local copy of function's base */ + /* main loop of interpreter */ + for (;;) { + Instruction i; + StkId ra; + vmfetch(); + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE) { + setobjs2s(L, ra, RB(i)); + vmbreak; + } + vmcase(OP_LOADK) { + TValue *rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADKX) { + TValue *rb; + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + rb = k + GETARG_Ax(*ci->u.l.savedpc++); + setobj2s(L, ra, rb); + vmbreak; + } + vmcase(OP_LOADBOOL) { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ + vmbreak; + } + vmcase(OP_LOADNIL) { + int b = GETARG_B(i); + do { + setnilvalue(ra++); + } while (b--); + vmbreak; + } + vmcase(OP_GETUPVAL) { + int b = GETARG_B(i); + setobj2s(L, ra, cl->upvals[b]->v); + vmbreak; + } + vmcase(OP_GETTABUP) { + TValue *upval = cl->upvals[GETARG_B(i)]->v; + TValue *rc = RKC(i); + gettableProtected(L, upval, rc, ra); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId rb = RB(i); + TValue *rc = RKC(i); + gettableProtected(L, rb, rc, ra); + vmbreak; + } + vmcase(OP_SETTABUP) { + TValue *upval = cl->upvals[GETARG_A(i)]->v; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, upval, rb, rc); + vmbreak; + } + vmcase(OP_SETUPVAL) { + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_upvalbarrier(L, uv); + vmbreak; + } + vmcase(OP_SETTABLE) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, ra, rb, rc); + vmbreak; + } + vmcase(OP_NEWTABLE) { + int b = GETARG_B(i); + int c = GETARG_C(i); + Table *t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_SELF) { + const TValue *aux; + StkId rb = RB(i); + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { + setobj2s(L, ra, aux); + } + else Protect(luaV_finishget(L, rb, rc, ra, aux)); + vmbreak; + } + vmcase(OP_ADD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(+, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numadd(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } + vmbreak; + } + vmcase(OP_SUB) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(-, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numsub(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } + vmbreak; + } + vmcase(OP_MUL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(*, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_nummul(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numdiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } + vmbreak; + } + vmcase(OP_BAND) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + vmbreak; + } + vmcase(OP_BOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + vmbreak; + } + vmcase(OP_BXOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + vmbreak; + } + vmcase(OP_SHL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } + vmbreak; + } + vmcase(OP_SHR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, -ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } + vmbreak; + } + vmcase(OP_MOD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_mod(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + lua_Number m; + luai_nummod(L, nb, nc, m); + setfltvalue(ra, m); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_div(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numidiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } + vmbreak; + } + vmcase(OP_POW) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numpow(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } + vmbreak; + } + vmcase(OP_UNM) { + TValue *rb = RB(i); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(ra, intop(-, 0, ib)); + } + else if (tonumber(rb, &nb)) { + setfltvalue(ra, luai_numunm(L, nb)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); + } + vmbreak; + } + vmcase(OP_BNOT) { + TValue *rb = RB(i); + lua_Integer ib; + if (tointeger(rb, &ib)) { + setivalue(ra, intop(^, ~l_castS2U(0), ib)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + } + vmbreak; + } + vmcase(OP_NOT) { + TValue *rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ + setbvalue(ra, res); + vmbreak; + } + vmcase(OP_LEN) { + Protect(luaV_objlen(L, ra, RB(i))); + vmbreak; + } + vmcase(OP_CONCAT) { + int b = GETARG_B(i); + int c = GETARG_C(i); + StkId rb; + L->top = base + c + 1; /* mark the end of concat operands */ + Protect(luaV_concat(L, c - b + 1)); + ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ + rb = base + b; + setobjs2s(L, ra, rb); + checkGC(L, (ra >= rb ? ra + 1 : rb)); + L->top = ci->top; /* restore top */ + vmbreak; + } + vmcase(OP_JMP) { + dojump(ci, i, 0); + vmbreak; + } + vmcase(OP_EQ) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + Protect( + if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LT) { + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_LE) { + Protect( + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); + ) + vmbreak; + } + vmcase(OP_TEST) { + if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) + ci->u.l.savedpc++; + else + donextjump(ci); + vmbreak; + } + vmcase(OP_TESTSET) { + TValue *rb = RB(i); + if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + ci->u.l.savedpc++; + else { + setobjs2s(L, ra, rb); + donextjump(ci); + } + vmbreak; + } + vmcase(OP_CALL) { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + if (luaD_precall(L, ra, nresults)) { /* C function? */ + if (nresults >= 0) + L->top = ci->top; /* adjust results */ + Protect((void)0); /* update 'base' */ + } + else { /* Lua function */ + ci = L->ci; + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_TAILCALL) { + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + Protect((void)0); /* update 'base' */ + } + else { + /* tail call: put called frame (n) in place of caller one (o) */ + CallInfo *nci = L->ci; /* called frame */ + CallInfo *oci = nci->previous; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + getproto(nfunc)->numparams; + int aux; + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobjs2s(L, ofunc + aux, nfunc + aux); + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); + goto newframe; /* restart luaV_execute over new Lua function */ + } + vmbreak; + } + vmcase(OP_RETURN) { + int b = GETARG_B(i); + if (cl->p->sizep > 0) luaF_close(L, base); + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ + return; /* external invocation: return */ + else { /* invocation via reentry: continue execution */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + goto newframe; /* restart luaV_execute over new Lua function */ + } + } + vmcase(OP_FORLOOP) { + if (ttisinteger(ra)) { /* integer loop? */ + lua_Integer step = ivalue(ra + 2); + lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ + lua_Integer limit = ivalue(ra + 1); + if ((0 < step) ? (idx <= limit) : (limit <= idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgivalue(ra, idx); /* update internal index... */ + setivalue(ra + 3, idx); /* ...and external index */ + } + } + else { /* floating loop */ + lua_Number step = fltvalue(ra + 2); + lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ + lua_Number limit = fltvalue(ra + 1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgfltvalue(ra, idx); /* update internal index... */ + setfltvalue(ra + 3, idx); /* ...and external index */ + } + } + vmbreak; + } + vmcase(OP_FORPREP) { + TValue *init = ra; + TValue *plimit = ra + 1; + TValue *pstep = ra + 2; + lua_Integer ilimit; + int stopnow; + if (ttisinteger(init) && ttisinteger(pstep) && + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { + /* all values are integer */ + lua_Integer initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, ivalue(pstep))); + } + else { /* try making all values floats */ + lua_Number ninit; lua_Number nlimit; lua_Number nstep; + if (!tonumber(plimit, &nlimit)) + luaG_runerror(L, "'for' limit must be a number"); + setfltvalue(plimit, nlimit); + if (!tonumber(pstep, &nstep)) + luaG_runerror(L, "'for' step must be a number"); + setfltvalue(pstep, nstep); + if (!tonumber(init, &ninit)) + luaG_runerror(L, "'for' initial value must be a number"); + setfltvalue(init, luai_numsub(L, ninit, nstep)); + } + ci->u.l.savedpc += GETARG_sBx(i); + vmbreak; + } + vmcase(OP_TFORCALL) { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L->top = cb + 3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i))); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + goto l_tforloop; + } + vmcase(OP_TFORLOOP) { + l_tforloop: + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + } + vmbreak; + } + vmcase(OP_SETLIST) { + int n = GETARG_B(i); + int c = GETARG_C(i); + unsigned int last; + Table *h; + if (n == 0) n = cast_int(L->top - ra) - 1; + if (c == 0) { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + c = GETARG_Ax(*ci->u.l.savedpc++); + } + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h->sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* preallocate it at once */ + for (; n > 0; n--) { + TValue *val = ra+n; + luaH_setint(L, h, last--, val); + luaC_barrierback(L, h, val); + } + L->top = ci->top; /* correct top (in case of previous open call) */ + vmbreak; + } + vmcase(OP_CLOSURE) { + Proto *p = cl->p->p[GETARG_Bx(i)]; + LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ + if (ncl == NULL) /* no match? */ + pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ + else + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, ra + 1); + vmbreak; + } + vmcase(OP_VARARG) { + int b = GETARG_B(i) - 1; /* required results */ + int j; + int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (n < 0) /* less arguments than parameters? */ + n = 0; /* no vararg arguments */ + if (b < 0) { /* B == 0? */ + b = n; /* get all var. arguments */ + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ + L->top = ra + n; + } + for (j = 0; j < b && j < n; j++) + setobjs2s(L, ra + j, base - n + j); + for (; j < b; j++) /* complete required results with nil */ + setnilvalue(ra + j); + vmbreak; + } + vmcase(OP_EXTRAARG) { + lua_assert(0); + vmbreak; + } + } + } +} + +/* }================================================================== */ + diff --git a/libs/lua/source/lzio.c b/libs/lua/source/lzio.c index 6f790944..0b03cf57 100644 --- a/libs/lua/source/lzio.c +++ b/libs/lua/source/lzio.c @@ -1,68 +1,68 @@ -/* -** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $ -** Buffered streams -** See Copyright Notice in lua.h -*/ - -#define lzio_c -#define LUA_CORE - -#include "lprefix.h" - - -#include - -#include "lua.h" - -#include "llimits.h" -#include "lmem.h" -#include "lstate.h" -#include "lzio.h" - - -int luaZ_fill (ZIO *z) { - size_t size; - lua_State *L = z->L; - const char *buff; - lua_unlock(L); - buff = z->reader(L, z->data, &size); - lua_lock(L); - if (buff == NULL || size == 0) - return EOZ; - z->n = size - 1; /* discount char being returned */ - z->p = buff; - return cast_uchar(*(z->p++)); -} - - -void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { - z->L = L; - z->reader = reader; - z->data = data; - z->n = 0; - z->p = NULL; -} - - -/* --------------------------------------------------------------- read --- */ -size_t luaZ_read (ZIO *z, void *b, size_t n) { - while (n) { - size_t m; - if (z->n == 0) { /* no bytes in buffer? */ - if (luaZ_fill(z) == EOZ) /* try to read more */ - return n; /* no more input; return number of missing bytes */ - else { - z->n++; /* luaZ_fill consumed first byte; put it back */ - z->p--; - } - } - m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ - memcpy(b, z->p, m); - z->n -= m; - z->p += m; - b = (char *)b + m; - n -= m; - } - return 0; -} - +/* +** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + +#define lzio_c +#define LUA_CORE + +#include "lprefix.h" + + +#include + +#include "lua.h" + +#include "llimits.h" +#include "lmem.h" +#include "lstate.h" +#include "lzio.h" + + +int luaZ_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ + z->p = buff; + return cast_uchar(*(z->p++)); +} + + +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t luaZ_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (z->n == 0) { /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + diff --git a/libs/minizip/include/CDirEntry.h b/libs/minizip/include/CDirEntry.h index 9c1ae0cc..12f0b9eb 100644 --- a/libs/minizip/include/CDirEntry.h +++ b/libs/minizip/include/CDirEntry.h @@ -1,215 +1,215 @@ -// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual -// Properties, Inc., EML Research, gGmbH, University of Heidelberg, -// and The University of Manchester. -// All rights reserved. - -// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual -// Properties, Inc. and EML Research, gGmbH. -// All rights reserved. - -#ifndef ZIPPER_CDirEntry -#define ZIPPER_CDirEntry - -#include -#include - -namespace zipper -{ - /** - * This class provides an OS independent interface to directory entries - * such as files and directories. - */ - class CDirEntry - { - public: - /** - * The character used to separate directory entries. - */ - static const std::string Separator; - - /** - * Check whether the directory entry specified by 'path' is - * a file. - * @param const std::string & path - * @return bool isFile - */ - static bool isFile(const std::string & path); - - /** - * Check whether the directory entry specified by 'path' is - * is a directory. - * @param const std::string & path - * @return bool isDir - */ - static bool isDir(const std::string & path); - - /** - * Check whether the directory entry specified by 'path' exists. - * @param const std::string & path - * @return bool exist - */ - static bool exist(const std::string & path); - - /** - * Check whether the directory entry specified by 'path' is - * is readable. - * @param const std::string & path - * @return bool isReadable - */ - static bool isReadable(const std::string & path); - - /** - * Check whether the directory entry specified by 'path' is - * writable. - * @param const std::string & path - * @return bool isWritable - */ - static bool isWritable(const std::string & path); - - /** - * Returns the base name, i.e., the directory path and the - * the suffix are removed from 'path'. - * @param const std::string & path - * @return std::string baseName - */ - static std::string baseName(const std::string & path); - - /** - * Returns the file name, i.e., the directory path is removed from 'path'. - * @param const std::string & path - * @return std::string fileName - */ - static std::string fileName(const std::string & path); - - /** - * Returns the directory path to the parent directoryu, i.e., - * the file name or directory name are removed from 'path'. - * @param const std::string & path - * @return std::string dirName - */ - static std::string dirName(const std::string & path); - - /** - * Returns the suffix, i.e., the directory path and the - * the base name are removed from 'path'. - * @param const std::string & path - * @return std::string basename - */ - static std::string suffix(const std::string & path); - - /** - * Create the directory 'dir' in the parent directory 'parent'. - * @param const std::string & dir - * @param const std::string & parent (Default: current working directory) - * @return bool success - */ - static bool createDir(const std::string & dir, - const std::string & parent = ""); - - /** - * Create a name for a temporary directory entry. The directory entry - * will be located in the directory given - * @param const std::string & dir - * @param const std::string & suffix - * @return std::string tmpName - */ - static std::string createTmpName(const std::string & dir, - const std::string & suffix); - - /** - * Move a file from. If to is the directory the filename of from is - * appended. - * @param const std::string & from - * @param const std::string & to - * @return bool success - */ - static bool move(const std::string & from, - const std::string & to); - - /** - * Removes a file or directory specified by path. - * @param const std::string & path - * @return bool success - */ - static bool remove(const std::string & path); - - /** - * Remove files or directories matching the pattern in directory dir. - * @param const std::string & pattern - * @param const std::string & dir - * @return bool success - */ - static bool removeFiles(const std::string & pattern, - const std::string & dir); - - /** - * Compiles the pattern to a patternList. Valid wildcards in the pattern are: - * '*' matches any number of characters and '?' matches exactly one character. - * @param const std::string & pattern - * @return std::vector< std::string > patternList - */ - static std::vector< std::string > compilePattern(const std::string & pattern); - - /** - * Compare the name against the pattern list and returns whether the - * name matches. The patternList can be created from a pattern by the - * compilePattern method. - * @param const std::string & name - * @param const std::vector< std::string > & patternList - * @return bool match - */ - static bool match(const std::string & name, - const std::vector< std::string > & patternList); - - /** - * Checks whether the given path is relative - * @return bool isRelative - */ - static bool isRelativePath(const std::string & path); - - /** - * Makes the absolute path relative to the path given in relativeTo - * @param std::string & absolutePath - * @param const std::string & relativeTo - * @return bool success - */ - static bool makePathRelative(std::string & absolutePath, - const std::string & relativeTo); - - /** - * Makes the relative path absolute to the path given in absoluteTo - * @param std::string & relativePath - * @param const std::string & absoluteTo - * @return bool success - */ - static bool makePathAbsolute(std::string & relativePath, - const std::string & absoluteTo); - - /** - * This method normalizes the path, i.e., - * it converts all '\' to '/' (only on WIN32) - * and collapses '^./' to '^', '/./' to '/', and '[^/]+/../' to '/' - * @param const std::string & path - * @return std::string normalizedPath - */ - static std::string normalize(const std::string & path); - - private: - /** - * This private methods checks whether the active section matches the - * specified patter. The section is automatically advanced to allow - * repeated calls. On the first call 'at' must be 0. The parameters - * 'at' and 'after' must not be changed outside this method. - * @param const std::string & name - * @param const std::string pattern - * @param std::string::size_type & at - * @param std::string::size_type & after - * @return bool match - */ - static bool matchInternal(const std::string & name, - const std::string pattern, - std::string::size_type & at, - std::string::size_type & after); - }; -} -#endif // ZIPPER_CDirEntry +// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual +// Properties, Inc., EML Research, gGmbH, University of Heidelberg, +// and The University of Manchester. +// All rights reserved. + +// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual +// Properties, Inc. and EML Research, gGmbH. +// All rights reserved. + +#ifndef ZIPPER_CDirEntry +#define ZIPPER_CDirEntry + +#include +#include + +namespace zipper +{ + /** + * This class provides an OS independent interface to directory entries + * such as files and directories. + */ + class CDirEntry + { + public: + /** + * The character used to separate directory entries. + */ + static const std::string Separator; + + /** + * Check whether the directory entry specified by 'path' is + * a file. + * @param const std::string & path + * @return bool isFile + */ + static bool isFile(const std::string & path); + + /** + * Check whether the directory entry specified by 'path' is + * is a directory. + * @param const std::string & path + * @return bool isDir + */ + static bool isDir(const std::string & path); + + /** + * Check whether the directory entry specified by 'path' exists. + * @param const std::string & path + * @return bool exist + */ + static bool exist(const std::string & path); + + /** + * Check whether the directory entry specified by 'path' is + * is readable. + * @param const std::string & path + * @return bool isReadable + */ + static bool isReadable(const std::string & path); + + /** + * Check whether the directory entry specified by 'path' is + * writable. + * @param const std::string & path + * @return bool isWritable + */ + static bool isWritable(const std::string & path); + + /** + * Returns the base name, i.e., the directory path and the + * the suffix are removed from 'path'. + * @param const std::string & path + * @return std::string baseName + */ + static std::string baseName(const std::string & path); + + /** + * Returns the file name, i.e., the directory path is removed from 'path'. + * @param const std::string & path + * @return std::string fileName + */ + static std::string fileName(const std::string & path); + + /** + * Returns the directory path to the parent directoryu, i.e., + * the file name or directory name are removed from 'path'. + * @param const std::string & path + * @return std::string dirName + */ + static std::string dirName(const std::string & path); + + /** + * Returns the suffix, i.e., the directory path and the + * the base name are removed from 'path'. + * @param const std::string & path + * @return std::string basename + */ + static std::string suffix(const std::string & path); + + /** + * Create the directory 'dir' in the parent directory 'parent'. + * @param const std::string & dir + * @param const std::string & parent (Default: current working directory) + * @return bool success + */ + static bool createDir(const std::string & dir, + const std::string & parent = ""); + + /** + * Create a name for a temporary directory entry. The directory entry + * will be located in the directory given + * @param const std::string & dir + * @param const std::string & suffix + * @return std::string tmpName + */ + static std::string createTmpName(const std::string & dir, + const std::string & suffix); + + /** + * Move a file from. If to is the directory the filename of from is + * appended. + * @param const std::string & from + * @param const std::string & to + * @return bool success + */ + static bool move(const std::string & from, + const std::string & to); + + /** + * Removes a file or directory specified by path. + * @param const std::string & path + * @return bool success + */ + static bool remove(const std::string & path); + + /** + * Remove files or directories matching the pattern in directory dir. + * @param const std::string & pattern + * @param const std::string & dir + * @return bool success + */ + static bool removeFiles(const std::string & pattern, + const std::string & dir); + + /** + * Compiles the pattern to a patternList. Valid wildcards in the pattern are: + * '*' matches any number of characters and '?' matches exactly one character. + * @param const std::string & pattern + * @return std::vector< std::string > patternList + */ + static std::vector< std::string > compilePattern(const std::string & pattern); + + /** + * Compare the name against the pattern list and returns whether the + * name matches. The patternList can be created from a pattern by the + * compilePattern method. + * @param const std::string & name + * @param const std::vector< std::string > & patternList + * @return bool match + */ + static bool match(const std::string & name, + const std::vector< std::string > & patternList); + + /** + * Checks whether the given path is relative + * @return bool isRelative + */ + static bool isRelativePath(const std::string & path); + + /** + * Makes the absolute path relative to the path given in relativeTo + * @param std::string & absolutePath + * @param const std::string & relativeTo + * @return bool success + */ + static bool makePathRelative(std::string & absolutePath, + const std::string & relativeTo); + + /** + * Makes the relative path absolute to the path given in absoluteTo + * @param std::string & relativePath + * @param const std::string & absoluteTo + * @return bool success + */ + static bool makePathAbsolute(std::string & relativePath, + const std::string & absoluteTo); + + /** + * This method normalizes the path, i.e., + * it converts all '\' to '/' (only on WIN32) + * and collapses '^./' to '^', '/./' to '/', and '[^/]+/../' to '/' + * @param const std::string & path + * @return std::string normalizedPath + */ + static std::string normalize(const std::string & path); + + private: + /** + * This private methods checks whether the active section matches the + * specified patter. The section is automatically advanced to allow + * repeated calls. On the first call 'at' must be 0. The parameters + * 'at' and 'after' must not be changed outside this method. + * @param const std::string & name + * @param const std::string pattern + * @param std::string::size_type & at + * @param std::string::size_type & after + * @return bool match + */ + static bool matchInternal(const std::string & name, + const std::string pattern, + std::string::size_type & at, + std::string::size_type & after); + }; +} +#endif // ZIPPER_CDirEntry diff --git a/libs/minizip/include/crypt.h b/libs/minizip/include/crypt.h index 46c63fb3..1fed063d 100644 --- a/libs/minizip/include/crypt.h +++ b/libs/minizip/include/crypt.h @@ -1,130 +1,130 @@ -/* crypt.h -- base code for traditional PKWARE encryption - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - Modifications for Info-ZIP crypting - Copyright (C) 2003 Terry Thorsen - - This code is a modified version of crypting code in Info-ZIP distribution - - Copyright (C) 1990-2000 Info-ZIP. All rights reserved. - - See the Info-ZIP LICENSE file version 2000-Apr-09 or later for terms of use - which also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - If you don't need crypting in your application, just define symbols - NOCRYPT and NOUNCRYPT. -*/ - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) -{ - unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an - * unpredictable manner on 16-bit systems; not a problem - * with any known compiler so far, though */ - - temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) -{ - (*(pkeys+0)) = CRC32((*(pkeys+0)), c); - (*(pkeys+1)) += (*(pkeys+0)) & 0xff; - (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; - { - register int keyshift = (int)((*(pkeys+1)) >> 24); - (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); - } - return c; -} - - -/*********************************************************************** - * Initialize the encryption keys and the random header according to - * the given password. - */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) -{ - *(pkeys+0) = 305419896L; - *(pkeys+1) = 591751049L; - *(pkeys+2) = 878082192L; - while (*passwd != 0) { - update_keys(pkeys,pcrc_32_tab,(int)*passwd); - passwd++; - } -} - -#define zdecode(pkeys,pcrc_32_tab,c) \ - (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) - -#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED - -#define RAND_HEAD_LEN 12 - /* "last resort" source for second part of crypt seed pattern */ -# ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ -# endif - -static int crypthead(const char* passwd, /* password string */ - unsigned char* buf, /* where to write header */ - int bufSize, - unsigned long* pkeys, - const unsigned long* pcrc_32_tab, - unsigned long crcForCrypting) -{ - int n; /* index in random header */ - int t; /* temporary */ - int c; /* random byte */ - unsigned char header[RAND_HEAD_LEN-2]; /* random header */ - static unsigned calls = 0; /* ensure different random header each time */ - - if (bufSize> 7) & 0xff; - header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); - } - /* Encrypt random header (last two bytes is high word of crc) */ - init_keys(passwd, pkeys, pcrc_32_tab); - for (n = 0; n < RAND_HEAD_LEN-2; n++) - { - buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); - } - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif +/* crypt.h -- base code for traditional PKWARE encryption + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + Modifications for Info-ZIP crypting + Copyright (C) 2003 Terry Thorsen + + This code is a modified version of crypting code in Info-ZIP distribution + + Copyright (C) 1990-2000 Info-ZIP. All rights reserved. + + See the Info-ZIP LICENSE file version 2000-Apr-09 or later for terms of use + which also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != 0) { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/libs/minizip/include/defs.h b/libs/minizip/include/defs.h index d89036c0..c618efc5 100644 --- a/libs/minizip/include/defs.h +++ b/libs/minizip/include/defs.h @@ -1,66 +1,66 @@ -#pragma once - -extern "C" -{ -#include -#include -#include -#include -#include -#include -#include - -#if (defined(_WIN32)) || (defined(_WIN64)) -# include -# include -#else -# include -# include -#endif - -#include -#include -#include -#define CASESENSITIVITY (0) -#define WRITEBUFFERSIZE (8192) -#define MAXFILENAME (256) - -#if (defined(_WIN32)) || (defined(_WIN64)) -#define USEWIN32IOAPI -#include "iowin32.h" -#endif -} - -#if (defined(_WIN32)) || (defined(_WIN64)) - #include -#endif - -#if (defined(_WIN32)) || (defined(_WIN64)) - #define EXCEPTION_CLASS std::exception -#else - #define EXCEPTION_CLASS std::runtime_error -#endif - - -#if (defined(_WIN64)) && (!defined(__APPLE__)) -#ifndef __USE_FILE_OFFSET64 -#define __USE_FILE_OFFSET64 -#endif -#ifndef __USE_LARGEFILE64 -#define __USE_LARGEFILE64 -#endif -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif -#ifndef _FILE_OFFSET_BIT -#define _FILE_OFFSET_BIT 64 -#endif -#endif - -#if (defined(_WIN32)) || (defined(_WIN64)) -# define MKDIR(d) _mkdir(d) -# define CHDIR(d) _chdir(d) -#else -# define MKDIR(d) mkdir(d, 0775) -# define CHDIR(d) chdir(d) -#endif +#pragma once + +extern "C" +{ +#include +#include +#include +#include +#include +#include +#include + +#if (defined(_WIN32)) || (defined(_WIN64)) +# include +# include +#else +# include +# include +#endif + +#include +#include +#include +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#if (defined(_WIN32)) || (defined(_WIN64)) +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +} + +#if (defined(_WIN32)) || (defined(_WIN64)) + #include +#endif + +#if (defined(_WIN32)) || (defined(_WIN64)) + #define EXCEPTION_CLASS std::exception +#else + #define EXCEPTION_CLASS std::runtime_error +#endif + + +#if (defined(_WIN64)) && (!defined(__APPLE__)) +#ifndef __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET64 +#endif +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#ifndef _FILE_OFFSET_BIT +#define _FILE_OFFSET_BIT 64 +#endif +#endif + +#if (defined(_WIN32)) || (defined(_WIN64)) +# define MKDIR(d) _mkdir(d) +# define CHDIR(d) _chdir(d) +#else +# define MKDIR(d) mkdir(d, 0775) +# define CHDIR(d) chdir(d) +#endif diff --git a/libs/minizip/include/ioapi.h b/libs/minizip/include/ioapi.h index d0eb38b1..5a9cadf5 100644 --- a/libs/minizip/include/ioapi.h +++ b/libs/minizip/include/ioapi.h @@ -1,177 +1,177 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _ZLIBIOAPI64_H -#define _ZLIBIOAPI64_H - -#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) -# ifndef __USE_FILE_OFFSET64 -# define __USE_FILE_OFFSET64 -# endif -# ifndef __USE_LARGEFILE64 -# define __USE_LARGEFILE64 -# endif -# ifndef _LARGEFILE64_SOURCE -# define _LARGEFILE64_SOURCE -# endif -# ifndef _FILE_OFFSET_BIT -# define _FILE_OFFSET_BIT 64 -# endif -#endif - -#include -#include -#include "zlib.h" - -#define USE_FILE32API - -#if defined(USE_FILE32API) -# define fopen64 fopen -# define ftello64 ftell -# define fseeko64 fseek -#else -# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) -# define fopen64 fopen -# define ftello64 ftello -# define fseeko64 fseeko -# endif -# ifdef _MSC_VER -# define fopen64 fopen -# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) -# define ftello64 _ftelli64 -# define fseeko64 _fseeki64 -# else /* old MSC */ -# define ftello64 ftell -# define fseeko64 fseek -# endif -# endif -#endif - -/* a type choosen by DEFINE */ -#ifdef HAVE_64BIT_INT_CUSTOM -typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; -#else -# ifdef HAS_STDINT_H -# include "stdint.h" - typedef uint64_t ZPOS64_T; -# else -# if defined(_MSC_VER) || defined(__BORLANDC__) - typedef unsigned __int64 ZPOS64_T; -# else - typedef unsigned long long int ZPOS64_T; -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_FILEFUNC_SEEK_CUR (1) -#define ZLIB_FILEFUNC_SEEK_END (2) -#define ZLIB_FILEFUNC_SEEK_SET (0) - -#define ZLIB_FILEFUNC_MODE_READ (1) -#define ZLIB_FILEFUNC_MODE_WRITE (2) -#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) -#define ZLIB_FILEFUNC_MODE_EXISTING (4) -#define ZLIB_FILEFUNC_MODE_CREATE (8) - -#ifndef ZCALLBACK -# if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \ - defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) -# define ZCALLBACK CALLBACK -# else -# define ZCALLBACK -# endif -#endif - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef voidpf (ZCALLBACK *opendisk_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); - -/* here is the "old" 32 bits structure structure */ -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_file; - opendisk_file_func zopendisk_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell_file_func ztell_file; - seek_file_func zseek_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc_def; - -typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); -typedef voidpf (ZCALLBACK *opendisk64_file_func)OF((voidpf opaque, voidpf stream, int number_disk, int mode)); - -typedef struct zlib_filefunc64_def_s -{ - open64_file_func zopen64_file; - opendisk64_file_func zopendisk64_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell64_file_func ztell64_file; - seek64_file_func zseek64_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc64_def; - -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); -void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); - -/* now internal definition, only for zip.c and unzip.h */ -typedef struct zlib_filefunc64_32_def_s -{ - zlib_filefunc64_def zfile_func64; - open_file_func zopen32_file; - opendisk_file_func zopendisk32_file; - tell_file_func ztell32_file; - seek_file_func zseek32_file; -} zlib_filefunc64_32_def; - -#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/ -/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/ -#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) -#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) - -voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); -voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)); -long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); -ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); - -void fill_zlib_filefunc64_32_def_from_filefunc32 OF((zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)); - -#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) -#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode))) -#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) -#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) - -#ifdef __cplusplus -} -#endif - -#endif +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) +# ifndef __USE_FILE_OFFSET64 +# define __USE_FILE_OFFSET64 +# endif +# ifndef __USE_LARGEFILE64 +# define __USE_LARGEFILE64 +# endif +# ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +# endif +# ifndef _FILE_OFFSET_BIT +# define _FILE_OFFSET_BIT 64 +# endif +#endif + +#include +#include +#include "zlib.h" + +#define USE_FILE32API + +#if defined(USE_FILE32API) +# define fopen64 fopen +# define ftello64 ftell +# define fseeko64 fseek +#else +# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) +# define fopen64 fopen +# define ftello64 ftello +# define fseeko64 fseeko +# endif +# ifdef _MSC_VER +# define fopen64 fopen +# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) +# define ftello64 _ftelli64 +# define fseeko64 _fseeki64 +# else /* old MSC */ +# define ftello64 ftell +# define fseeko64 fseek +# endif +# endif +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +# ifdef HAS_STDINT_H +# include "stdint.h" + typedef uint64_t ZPOS64_T; +# else +# if defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned __int64 ZPOS64_T; +# else + typedef unsigned long long int ZPOS64_T; +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +#ifndef ZCALLBACK +# if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \ + defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +# define ZCALLBACK CALLBACK +# else +# define ZCALLBACK +# endif +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef voidpf (ZCALLBACK *opendisk_file_func) OF((voidpf opaque, voidpf stream, int number_disk, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + opendisk_file_func zopendisk_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); +typedef voidpf (ZCALLBACK *opendisk64_file_func)OF((voidpf opaque, voidpf stream, int number_disk, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + opendisk64_file_func zopendisk64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + opendisk_file_func zopendisk32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/ +/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/ +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32 OF((zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/minizip/include/ioapi_buf.h b/libs/minizip/include/ioapi_buf.h index 2feb777b..fa2ebef8 100644 --- a/libs/minizip/include/ioapi_buf.h +++ b/libs/minizip/include/ioapi_buf.h @@ -1,54 +1,54 @@ -/* ioapi_buf.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - This version of ioapi is designed to buffer IO. - - Copyright (C) 1998-2003 Gilles Vollant - (C) 2012-2014 Nathan Moinvaziri - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _IOAPI_BUF_H -#define _IOAPI_BUF_H - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" - -#define IOBUF_BUFFERSIZE (64 * 1024) - -#ifdef __cplusplus -extern "C" { -#endif - -voidpf ZCALLBACK fopen_buf_func OF((voidpf opaque,const char* filename,int mode)); -voidpf ZCALLBACK fopen64_buf_func OF((voidpf opaque,const char* filename,int mode)); -voidpf ZCALLBACK fopendisk_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); -voidpf ZCALLBACK fopendisk64_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); -uLong ZCALLBACK fread_buf_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); -uLong ZCALLBACK fwrite_buf_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); -long ZCALLBACK ftell_buf_func OF((voidpf opaque,voidpf stream)); -ZPOS64_T ZCALLBACK ftell64_buf_func OF((voidpf opaque, voidpf stream)); -long ZCALLBACK fseek_buf_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); -long ZCALLBACK fseek64_buf_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -int ZCALLBACK fclose_buf_func OF((voidpf opaque,voidpf stream)); -int ZCALLBACK ferror_buf_func OF((voidpf opaque,voidpf stream)); - -typedef struct ourbuffer_s { - zlib_filefunc_def filefunc; - zlib_filefunc64_def filefunc64; -} ourbuffer_t; - -void fill_buffer_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); -void fill_buffer_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); - -#ifdef __cplusplus -} -#endif - -#endif +/* ioapi_buf.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + This version of ioapi is designed to buffer IO. + + Copyright (C) 1998-2003 Gilles Vollant + (C) 2012-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _IOAPI_BUF_H +#define _IOAPI_BUF_H + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + +#define IOBUF_BUFFERSIZE (64 * 1024) + +#ifdef __cplusplus +extern "C" { +#endif + +voidpf ZCALLBACK fopen_buf_func OF((voidpf opaque,const char* filename,int mode)); +voidpf ZCALLBACK fopen64_buf_func OF((voidpf opaque,const char* filename,int mode)); +voidpf ZCALLBACK fopendisk_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); +voidpf ZCALLBACK fopendisk64_buf_func OF((voidpf opaque, voidpf stream_cd, int number_disk, int mode)); +uLong ZCALLBACK fread_buf_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); +uLong ZCALLBACK fwrite_buf_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); +long ZCALLBACK ftell_buf_func OF((voidpf opaque,voidpf stream)); +ZPOS64_T ZCALLBACK ftell64_buf_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK fseek_buf_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); +long ZCALLBACK fseek64_buf_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK fclose_buf_func OF((voidpf opaque,voidpf stream)); +int ZCALLBACK ferror_buf_func OF((voidpf opaque,voidpf stream)); + +typedef struct ourbuffer_s { + zlib_filefunc_def filefunc; + zlib_filefunc64_def filefunc64; +} ourbuffer_t; + +void fill_buffer_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); +void fill_buffer_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def, ourbuffer_t *ourbuf)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/minizip/include/ioapi_mem.h b/libs/minizip/include/ioapi_mem.h index 1c2002f2..e0816c27 100644 --- a/libs/minizip/include/ioapi_mem.h +++ b/libs/minizip/include/ioapi_mem.h @@ -1,55 +1,55 @@ -/* ioapi_mem.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - This version of ioapi is designed to access memory rather than files. - We do use a region of memory to put data in to and take it out of. We do - not have auto-extending buffers and do not inform anyone else that the - data has been written. It is really intended for accessing a zip archive - embedded in an application such that I can write an installer with no - external files. - - Copyright (C) 1998-2003 Gilles Vollant - (C) 2003 Justin Fletcher - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _IOAPI_MEM_H -#define _IOAPI_MEM_H - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -voidpf ZCALLBACK fopen_mem_func OF((voidpf opaque,const char* filename,int mode)); -voidpf ZCALLBACK fopendisk_mem_func OF((voidpf opaque, voidpf stream, int number_disk, int mode)); -uLong ZCALLBACK fread_mem_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); -uLong ZCALLBACK fwrite_mem_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); -long ZCALLBACK ftell_mem_func OF((voidpf opaque,voidpf stream)); -long ZCALLBACK fseek_mem_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); -int ZCALLBACK fclose_mem_func OF((voidpf opaque,voidpf stream)); -int ZCALLBACK ferror_mem_func OF((voidpf opaque,voidpf stream)); - -typedef struct ourmemory_s { - char *base; /* Base of the region of memory we're using */ - uLong size; /* Size of the region of memory we're using */ - uLong limit; /* Furthest we've written */ - uLong cur_offset; /* Current offset in the area */ - int grow; /* Growable memory buffer */ -} ourmemory_t; - -void fill_memory_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourmemory_t *ourmem)); - -#ifdef __cplusplus -} -#endif - -#endif +/* ioapi_mem.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + This version of ioapi is designed to access memory rather than files. + We do use a region of memory to put data in to and take it out of. We do + not have auto-extending buffers and do not inform anyone else that the + data has been written. It is really intended for accessing a zip archive + embedded in an application such that I can write an installer with no + external files. + + Copyright (C) 1998-2003 Gilles Vollant + (C) 2003 Justin Fletcher + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _IOAPI_MEM_H +#define _IOAPI_MEM_H + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +voidpf ZCALLBACK fopen_mem_func OF((voidpf opaque,const char* filename,int mode)); +voidpf ZCALLBACK fopendisk_mem_func OF((voidpf opaque, voidpf stream, int number_disk, int mode)); +uLong ZCALLBACK fread_mem_func OF((voidpf opaque,voidpf stream,void* buf,uLong size)); +uLong ZCALLBACK fwrite_mem_func OF((voidpf opaque,voidpf stream,const void* buf,uLong size)); +long ZCALLBACK ftell_mem_func OF((voidpf opaque,voidpf stream)); +long ZCALLBACK fseek_mem_func OF((voidpf opaque,voidpf stream,uLong offset,int origin)); +int ZCALLBACK fclose_mem_func OF((voidpf opaque,voidpf stream)); +int ZCALLBACK ferror_mem_func OF((voidpf opaque,voidpf stream)); + +typedef struct ourmemory_s { + char *base; /* Base of the region of memory we're using */ + uLong size; /* Size of the region of memory we're using */ + uLong limit; /* Furthest we've written */ + uLong cur_offset; /* Current offset in the area */ + int grow; /* Growable memory buffer */ +} ourmemory_t; + +void fill_memory_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def, ourmemory_t *ourmem)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/minizip/include/iowin32.h b/libs/minizip/include/iowin32.h index 466e1d2f..d86b6a42 100644 --- a/libs/minizip/include/iowin32.h +++ b/libs/minizip/include/iowin32.h @@ -1,33 +1,33 @@ -/* iowin32.h -- IO base function header for compress/uncompress .zip - Version 1.1, February 14h, 2010 - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _IOWIN32_H -#define _IOWIN32_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); -void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); - -#ifdef __cplusplus -} -#endif - -#endif +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _IOWIN32_H +#define _IOWIN32_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/minizip/include/tools.h b/libs/minizip/include/tools.h index 5d0ab63f..2b2c9cb7 100644 --- a/libs/minizip/include/tools.h +++ b/libs/minizip/include/tools.h @@ -1,20 +1,20 @@ -#pragma once - -#include -#include -#include - - -namespace zipper -{ - void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned long& result_crc); - bool isLargeFile(std::istream& input_stream); - bool checkFileExists(const std::string& filename); - bool makedir(const std::string& newdir); - void removeFolder(const std::string& foldername); - std::string parentDirectory(const std::string& filepath); - std::string currentPath(); - bool isDirectory(const std::string& path); - std::vector filesFromDirectory(const std::string& path); - std::string fileNameFromPath(const std::string& path); -} +#pragma once + +#include +#include +#include + + +namespace zipper +{ + void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned long& result_crc); + bool isLargeFile(std::istream& input_stream); + bool checkFileExists(const std::string& filename); + bool makedir(const std::string& newdir); + void removeFolder(const std::string& foldername); + std::string parentDirectory(const std::string& filepath); + std::string currentPath(); + bool isDirectory(const std::string& path); + std::vector filesFromDirectory(const std::string& path); + std::string fileNameFromPath(const std::string& path); +} diff --git a/libs/minizip/include/unzip.h b/libs/minizip/include/unzip.h index 22c830f5..81e98c60 100644 --- a/libs/minizip/include/unzip.h +++ b/libs/minizip/include/unzip.h @@ -1,316 +1,316 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications of Unzip for Zip64 - Copyright (C) 2007-2008 Even Rouault - Modifications for Zip64 support on both zip and unzip - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _UNZ_H -#define _UNZ_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#ifdef HAVE_BZIP2 -#include "bzlib.h" -#endif - -#define Z_BZIP2ED 12 - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info64_s -{ - ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ - uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info64; - -typedef struct unz_global_info_s -{ - uLong number_entry; /* total number of entries in the central dir on this disk */ - uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info64_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - ZPOS64_T compressed_size; /* compressed size 8 bytes */ - ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; - ZPOS64_T disk_offset; - uLong size_file_extra_internal; -} unz_file_info64; - -typedef struct unz_file_info_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - uLong compressed_size; /* compressed size 4 bytes */ - uLong uncompressed_size; /* uncompressed size 4 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; - uLong disk_offset; -} unz_file_info; - -/***************************************************************************/ -/* Opening and close a zip file */ - -extern unzFile ZEXPORT unzOpen OF((const char *path)); -extern unzFile ZEXPORT unzOpen64 OF((const void *path)); -/* Open a Zip file. - - path should contain the full pathname (by example, on a Windows XP computer - "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". - return NULL if zipfile cannot be opened or doesn't exist - return unzFile handle if no error - - NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the - open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path - is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ - -extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); -/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */ -extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); -/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile, - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - - return UNZ_OK if there is no error */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); -extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); -/* Write info about the ZipFile in the *pglobal_info structure. - - return UNZ_OK if no error */ - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *comment, uLong comment_size)); -/* Get the global comment string of the ZipFile, in the comment buffer. - - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 */ - -/***************************************************************************/ -/* Reading the content of the current zipfile, you can open it, read data from it, and close it - (you can close it before reading all the file) */ - -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); -/* Open for reading data the current file in the zipfile. - - return UNZ_OK if no error */ - -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); -/* Open for reading data the current file in the zipfile. - password is a crypting password - - return UNZ_OK if no error */ - -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); -/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 *method will receive method of compression, *level will receive level of compression - - NOTE: you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL */ - -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); -/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */ - -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); -/* Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); -extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); -/* Get Info about the current file - - pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file - filename if != NULL, the file name string will be copied in filename - filename_size is the size of the filename buffer - extrafield if != NULL, the extra field information from the central header will be copied in to - extrafield_size is the size of the extraField buffer - comment if != NULL, the comment string of the file will be copied in to - comment_size is the size of the comment buffer */ - -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); - -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); -/* Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf == NULL, it return the size of the local extra field - if buf != NULL, len is the size of the buffer, the extra header is copied in buf. - - return number of bytes copied in buf, or (if <0) the error code */ - -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); -/* Close the file in zip opened with unzOpenCurrentFile - - return UNZ_CRCERROR if all the file was read but the CRC is not good */ - -/***************************************************************************/ -/* Browse the directory of the zipfile */ - -typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2); -typedef int (*unzIteratorFunction)(unzFile file); -typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size); - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* Set the current file of the zipfile to the first file. - - return UNZ_OK if no error */ - -extern int ZEXPORT unzGoToFirstFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); -/* Set the current file of the zipfile to the first file and retrieves the current info on success. - Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo. - - return UNZ_OK if no error */ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* Set the current file of the zipfile to the next file. - - return UNZ_OK if no error - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ - -extern int ZEXPORT unzGoToNextFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); -/* Set the current file of the zipfile to the next file and retrieves the current - info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo. - - return UNZ_OK if no error - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ - -extern int ZEXPORT unzLocateFile OF((unzFile file, const char *filename, unzFileNameComparer filename_compare_func)); -/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function. - - return UNZ_OK if the file is found (it becomes the current file) - return UNZ_END_OF_LIST_OF_FILE if the file is not found */ - -/***************************************************************************/ -/* Raw access to zip file */ - -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; /* offset in zip file directory */ - uLong num_of_file; /* # of file */ -} unz_file_pos; - -extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos)); -extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos)); - -typedef struct unz64_file_pos_s -{ - ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ - ZPOS64_T num_of_file; /* # of file */ -} unz64_file_pos; - -extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos)); -extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos)); - -extern uLong ZEXPORT unzGetOffset OF((unzFile file)); -extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file)); -/* Get the current file offset */ - -extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos)); -extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos)); -/* Set the current file offset */ - -extern z_off_t ZEXPORT unztell OF((unzFile file)); -extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); -/* return current position in uncompressed data */ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* return 1 if the end of file was reached, 0 elsewhere */ - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif - -#endif /* _UNZ_H */ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _UNZ_H +#define _UNZ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in the central dir on this disk */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + ZPOS64_T disk_offset; + uLong size_file_extra_internal; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + uLong disk_offset; +} unz_file_info; + +/***************************************************************************/ +/* Opening and close a zip file */ + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* Open a Zip file. + + path should contain the full pathname (by example, on a Windows XP computer + "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". + return NULL if zipfile cannot be opened or doesn't exist + return unzFile handle if no error + + NOTE: The "64" function take a const void* pointer, because the path is just the value passed to the + open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); +/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */ +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, zlib_filefunc64_def* pzlib_filefunc_def)); +/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile, + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + + return UNZ_OK if there is no error */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); +/* Write info about the ZipFile in the *pglobal_info structure. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *comment, uLong comment_size)); +/* Get the global comment string of the ZipFile, in the comment buffer. + + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 */ + +/***************************************************************************/ +/* Reading the content of the current zipfile, you can open it, read data from it, and close it + (you can close it before reading all the file) */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* Open for reading data the current file in the zipfile. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); +/* Open for reading data the current file in the zipfile. + password is a crypting password + + return UNZ_OK if no error */ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); +/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 *method will receive method of compression, *level will receive level of compression + + NOTE: you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL */ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); +/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); +/* Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); +/* Get Info about the current file + + pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file + filename if != NULL, the file name string will be copied in filename + filename_size is the size of the filename buffer + extrafield if != NULL, the extra field information from the central header will be copied in to + extrafield_size is the size of the extraField buffer + comment if != NULL, the comment string of the file will be copied in to + comment_size is the size of the comment buffer */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); +/* Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf == NULL, it return the size of the local extra field + if buf != NULL, len is the size of the buffer, the extra header is copied in buf. + + return number of bytes copied in buf, or (if <0) the error code */ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* Close the file in zip opened with unzOpenCurrentFile + + return UNZ_CRCERROR if all the file was read but the CRC is not good */ + +/***************************************************************************/ +/* Browse the directory of the zipfile */ + +typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2); +typedef int (*unzIteratorFunction)(unzFile file); +typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size); + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* Set the current file of the zipfile to the first file. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGoToFirstFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); +/* Set the current file of the zipfile to the first file and retrieves the current info on success. + Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo. + + return UNZ_OK if no error */ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* Set the current file of the zipfile to the next file. + + return UNZ_OK if no error + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ + +extern int ZEXPORT unzGoToNextFile2 OF((unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size)); +/* Set the current file of the zipfile to the next file and retrieves the current + info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo. + + return UNZ_OK if no error + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */ + +extern int ZEXPORT unzLocateFile OF((unzFile file, const char *filename, unzFileNameComparer filename_compare_func)); +/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function. + + return UNZ_OK if the file is found (it becomes the current file) + return UNZ_END_OF_LIST_OF_FILE if the file is not found */ + +/***************************************************************************/ +/* Raw access to zip file */ + +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos OF((unzFile file, unz_file_pos* file_pos)); +extern int ZEXPORT unzGoToFilePos OF((unzFile file, unz_file_pos* file_pos)); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64 OF((unzFile file, unz64_file_pos* file_pos)); +extern int ZEXPORT unzGoToFilePos64 OF((unzFile file, const unz64_file_pos* file_pos)); + +extern uLong ZEXPORT unzGetOffset OF((unzFile file)); +extern ZPOS64_T ZEXPORT unzGetOffset64 OF((unzFile file)); +/* Get the current file offset */ + +extern int ZEXPORT unzSetOffset OF((unzFile file, uLong pos)); +extern int ZEXPORT unzSetOffset64 OF((unzFile file, ZPOS64_T pos)); +/* Set the current file offset */ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* return current position in uncompressed data */ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* return 1 if the end of file was reached, 0 elsewhere */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _UNZ_H */ diff --git a/libs/minizip/include/unzipper.h b/libs/minizip/include/unzipper.h index e1e6556f..0c1a6968 100644 --- a/libs/minizip/include/unzipper.h +++ b/libs/minizip/include/unzipper.h @@ -1,88 +1,88 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace zipper { - - class ZipEntry; - - class Unzipper - { - public: - Unzipper(std::istream& buffer); - Unzipper(std::vector& buffer); - Unzipper(const std::string& zipname); - Unzipper(const std::string& zipname, const std::string& password); - - ~Unzipper(void); - - std::vector entries(); - - bool extract(const std::string& destination, const std::map& alternativeNames); - bool extract(const std::string& destination=std::string()); - bool extractEntry(const std::string& name, const std::string& destination = std::string()); - bool extractEntryToStream(const std::string& name, std::ostream& stream); - bool extractEntryToMemory(const std::string& name, std::vector& vec); - - void close(); - - private: - std::string m_password; - std::string m_zipname; - std::istream& m_ibuffer; - std::vector& m_vecbuffer; - bool m_usingMemoryVector; - bool m_usingStream; - bool m_open; - - struct Impl; - Impl* m_impl; - }; - - - class ZipEntry - { - private: - typedef struct - { - unsigned int tm_sec; - unsigned int tm_min; - unsigned int tm_hour; - unsigned int tm_mday; - unsigned int tm_mon; - unsigned int tm_year; - } tm_s; - - public: - ZipEntry(const std::string& name, unsigned long long int compressed_size, unsigned long long int uncompressed_size, - int year, int month, int day, int hour, int minute, int second, unsigned long dosdate) - : name(name), compressedSize(compressed_size), uncompressedSize(uncompressed_size), dosdate(dosdate) - { - // timestamp YYYY-MM-DD HH:MM:SS - std::stringstream str; - str << year << "-" << month << "-" << day << - " " << hour << ":" << minute << ":" << second; - timestamp = str.str(); - - unixdate.tm_year = year; - unixdate.tm_mon = month; - unixdate.tm_mday = day; - unixdate.tm_hour = hour; - unixdate.tm_min = minute; - unixdate.tm_sec = second; - } - - bool valid() { return !name.empty(); } - - std::string name, timestamp; - unsigned long long int compressedSize, uncompressedSize; - unsigned long dosdate; - tm_s unixdate; - }; -} +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace zipper { + + class ZipEntry; + + class Unzipper + { + public: + Unzipper(std::istream& buffer); + Unzipper(std::vector& buffer); + Unzipper(const std::string& zipname); + Unzipper(const std::string& zipname, const std::string& password); + + ~Unzipper(void); + + std::vector entries(); + + bool extract(const std::string& destination, const std::map& alternativeNames); + bool extract(const std::string& destination=std::string()); + bool extractEntry(const std::string& name, const std::string& destination = std::string()); + bool extractEntryToStream(const std::string& name, std::ostream& stream); + bool extractEntryToMemory(const std::string& name, std::vector& vec); + + void close(); + + private: + std::string m_password; + std::string m_zipname; + std::istream& m_ibuffer; + std::vector& m_vecbuffer; + bool m_usingMemoryVector; + bool m_usingStream; + bool m_open; + + struct Impl; + Impl* m_impl; + }; + + + class ZipEntry + { + private: + typedef struct + { + unsigned int tm_sec; + unsigned int tm_min; + unsigned int tm_hour; + unsigned int tm_mday; + unsigned int tm_mon; + unsigned int tm_year; + } tm_s; + + public: + ZipEntry(const std::string& name, unsigned long long int compressed_size, unsigned long long int uncompressed_size, + int year, int month, int day, int hour, int minute, int second, unsigned long dosdate) + : name(name), compressedSize(compressed_size), uncompressedSize(uncompressed_size), dosdate(dosdate) + { + // timestamp YYYY-MM-DD HH:MM:SS + std::stringstream str; + str << year << "-" << month << "-" << day << + " " << hour << ":" << minute << ":" << second; + timestamp = str.str(); + + unixdate.tm_year = year; + unixdate.tm_mon = month; + unixdate.tm_mday = day; + unixdate.tm_hour = hour; + unixdate.tm_min = minute; + unixdate.tm_sec = second; + } + + bool valid() { return !name.empty(); } + + std::string name, timestamp; + unsigned long long int compressedSize, uncompressedSize; + unsigned long dosdate; + tm_s unixdate; + }; +} diff --git a/libs/minizip/include/zip.h b/libs/minizip/include/zip.h index 3f3a30be..2387f63e 100644 --- a/libs/minizip/include/zip.h +++ b/libs/minizip/include/zip.h @@ -1,200 +1,200 @@ -/* zip.h -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#ifndef _ZIP_H -#define _ZIP_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -# include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -# include "ioapi.h" -#endif - -#ifdef HAVE_BZIP2 -# include "bzlib.h" -#endif - -#define Z_BZIP2ED 12 - -#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagzipFile__ { int unused; } zipFile__; -typedef zipFile__ *zipFile; -#else -typedef voidp zipFile; -#endif - -#define ZIP_OK (0) -#define ZIP_EOF (0) -#define ZIP_ERRNO (Z_ERRNO) -#define ZIP_PARAMERROR (-102) -#define ZIP_BADZIPFILE (-103) -#define ZIP_INTERNALERROR (-104) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif -/* default memLevel */ - -/* tm_zip contain date/time info */ -typedef struct tm_zip_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_zip; - -typedef struct -{ - tm_zip tmz_date; /* date in understandable format */ - uLong dosDate; /* if dos_date == 0, tmu_date is used */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -/***************************************************************************/ -/* Writing a zip file */ - -extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); -extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); -/* Create a zipfile. - - pathname should contain the full pathname (by example, on a Windows XP computer - "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". - - return NULL if zipfile cannot be opened - return zipFile handle if no error - - If the file pathname exist and append == APPEND_STATUS_CREATEAFTER, the zip - will be created at the end of the file. (useful if the file contain a self extractor code) - If the file pathname exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing - zip (be sure you don't add file that doesn't exist) - - NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, - you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy - the file you did not want delete. */ - -extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def)); - -extern zipFile ZEXPORT zipOpen3 OF((const char *pathname, int append, ZPOS64_T disk_size, - zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); -/* Same as zipOpen2 but allows specification of spanned zip size */ - -extern zipFile ZEXPORT zipOpen3_64 OF((const void *pathname, int append, ZPOS64_T disk_size, - zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level)); -/* Open a file in the ZIP for writing. - - filename : the filename in zip (if NULL, '-' without quote will be used - *zipfi contain supplemental information - extrafield_local buffer to store the local header extra field data, can be NULL - size_extrafield_local size of extrafield_local buffer - extrafield_global buffer to store the global header extra field data, can be NULL - size_extrafield_global size of extrafield_local buffer - comment buffer for comment string - method contain the compression method (0 for store, Z_DEFLATED for deflate) - level contain the level of compression (can be Z_DEFAULT_COMPRESSION) - zip64 is set to 1 if a zip64 extended information block should be added to the local file header. - this MUST be '1' if the uncompressed size is >= 0xffffffff. */ - -extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); -/* Same as zipOpenNewFileInZip with zip64 support */ - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw)); -/* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */ - -extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); -/* Same as zipOpenNewFileInZip3 with zip64 support */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, - int strategy, const char* password, uLong crcForCrypting)); -/* Same as zipOpenNewFileInZip2, except - windowBits, memLevel, strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCrypting : crc of file to compress (needed for crypting) */ - -extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, - int strategy, const char* password, uLong crcForCrypting, int zip64)); -/* Same as zipOpenNewFileInZip3 with zip64 support */ - -extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, - int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase)); -/* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */ - -extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, - int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64)); -/* Same as zipOpenNewFileInZip4 with zip64 support */ - -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); -/* Write data in the zipfile */ - -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); -/* Close the current file in the zipfile */ - -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); -extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); -/* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 - uncompressed_size and crc32 are value for the uncompressed size */ - -extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); -/* Close the zipfile */ - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif - -#endif /* _ZIP_H */ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#ifndef _ZIP_H +#define _ZIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +# include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +# include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +# include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +/***************************************************************************/ +/* Writing a zip file */ + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* Create a zipfile. + + pathname should contain the full pathname (by example, on a Windows XP computer + "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". + + return NULL if zipfile cannot be opened + return zipFile handle if no error + + If the file pathname exist and append == APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. (useful if the file contain a self extractor code) + If the file pathname exist and append == APPEND_STATUS_ADDINZIP, we will add files in existing + zip (be sure you don't add file that doesn't exist) + + NOTE: There is no delete function into a zipfile. If you want delete file into a zipfile, + you must open a zipfile, and create another. Of course, you can use RAW reading and writing to copy + the file you did not want delete. */ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, int append, zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen3 OF((const char *pathname, int append, ZPOS64_T disk_size, + zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); +/* Same as zipOpen2 but allows specification of spanned zip size */ + +extern zipFile ZEXPORT zipOpen3_64 OF((const void *pathname, int append, ZPOS64_T disk_size, + zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level)); +/* Open a file in the ZIP for writing. + + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + extrafield_local buffer to store the local header extra field data, can be NULL + size_extrafield_local size of extrafield_local buffer + extrafield_global buffer to store the global header extra field data, can be NULL + size_extrafield_global size of extrafield_local buffer + comment buffer for comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. */ + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); +/* Same as zipOpenNewFileInZip with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw)); +/* Same as zipOpenNewFileInZip, except if raw=1, we write raw file */ + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); +/* Same as zipOpenNewFileInZip3 with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, + int strategy, const char* password, uLong crcForCrypting)); +/* Same as zipOpenNewFileInZip2, except + windowBits, memLevel, strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) */ + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, + int strategy, const char* password, uLong crcForCrypting, int zip64)); +/* Same as zipOpenNewFileInZip3 with zip64 support */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, + int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase)); +/* Same as zipOpenNewFileInZip3 except versionMadeBy & flag fields */ + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, + int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64)); +/* Same as zipOpenNewFileInZip4 with zip64 support */ + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); +/* Write data in the zipfile */ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* Close the current file in the zipfile */ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); +/* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size */ + +extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); +/* Close the zipfile */ + +/***************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* _ZIP_H */ diff --git a/libs/minizip/include/zipper.h b/libs/minizip/include/zipper.h index 56fb5f21..006fa822 100644 --- a/libs/minizip/include/zipper.h +++ b/libs/minizip/include/zipper.h @@ -1,43 +1,43 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace zipper { - - class Zipper - { - public: - // Minizip options/params: - // -o -a -0 -1 -9 -j - enum zipFlags { Overwrite = 0x01, Append = 0x02, Store = 0x04, Faster = 0x08, Better = 0x10, NoPaths = 0x20 }; - - Zipper(std::iostream& buffer); - Zipper(std::vector& buffer); - Zipper(const std::string& zipname); - Zipper(const std::string& zipname, const std::string& password); - - ~Zipper(void); - - bool add(std::istream& source, const std::string& nameInZip = std::string(), zipFlags flags = Better); - bool add(const std::string& fileOrFolderPath, zipFlags flags = Better); - - void open(); - void close(); - - private: - std::string m_password; - std::string m_zipname; - std::iostream& m_obuffer; - std::vector& m_vecbuffer; - bool m_usingMemoryVector; - bool m_usingStream; - bool m_open; - - struct Impl; - Impl* m_impl; - }; -} +#pragma once + +#include +#include +#include +#include +#include + +namespace zipper { + + class Zipper + { + public: + // Minizip options/params: + // -o -a -0 -1 -9 -j + enum zipFlags { Overwrite = 0x01, Append = 0x02, Store = 0x04, Faster = 0x08, Better = 0x10, NoPaths = 0x20 }; + + Zipper(std::iostream& buffer); + Zipper(std::vector& buffer); + Zipper(const std::string& zipname); + Zipper(const std::string& zipname, const std::string& password); + + ~Zipper(void); + + bool add(std::istream& source, const std::string& nameInZip = std::string(), zipFlags flags = Better); + bool add(const std::string& fileOrFolderPath, zipFlags flags = Better); + + void open(); + void close(); + + private: + std::string m_password; + std::string m_zipname; + std::iostream& m_obuffer; + std::vector& m_vecbuffer; + bool m_usingMemoryVector; + bool m_usingStream; + bool m_open; + + struct Impl; + Impl* m_impl; + }; +} diff --git a/libs/minizip/source/CDirEntry.cpp b/libs/minizip/source/CDirEntry.cpp index 5f6c4e48..d125b963 100644 --- a/libs/minizip/source/CDirEntry.cpp +++ b/libs/minizip/source/CDirEntry.cpp @@ -1,622 +1,622 @@ -// Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual -// Properties, Inc., University of Heidelberg, and The University -// of Manchester. -// All rights reserved. - -// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual -// Properties, Inc., EML Research, gGmbH, University of Heidelberg, -// and The University of Manchester. -// All rights reserved. - -// Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual -// Properties, Inc. and EML Research, gGmbH. -// All rights reserved. - -#include -#include -#include - -#ifdef WIN32 -# include -# include -typedef struct _stat STAT; -# define stat _stat -# define S_IFREG _S_IFREG -# define S_IFDIR _S_IFDIR -# define access _access -# define mkdir _mkdir -# define rmdir _rmdir -#else -typedef struct stat STAT; -# include -# include -#endif // WIN32 - -#include "CDirEntry.h" - -#include - -#include - -using namespace zipper; - -#ifdef WIN32 -const std::string CDirEntry::Separator = "\\"; -#else -const std::string CDirEntry::Separator = "/"; -#endif - -bool CDirEntry::isFile(const std::string & path) -{ - STAT st; - - if (stat(path.c_str(), & st) == -1) return false; - -#ifdef WIN32 - return ((st.st_mode & S_IFREG) == S_IFREG); -#else - return S_ISREG(st.st_mode); -#endif -} - -bool CDirEntry::isDir(const std::string & path) -{ - STAT st; - - if (stat(path.c_str(), & st) == -1) return false; - -#ifdef WIN32 - return ((st.st_mode & S_IFDIR) == S_IFDIR); -#else - return S_ISDIR(st.st_mode); -#endif -} - -bool CDirEntry::exist(const std::string & path) -{ - STAT st; - - if (stat(path.c_str(), & st) == -1) return false; - -#ifdef WIN32 - return ((st.st_mode & S_IFREG) == S_IFREG || - (st.st_mode & S_IFDIR) == S_IFDIR); -#else - return (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)); -#endif -} - -bool CDirEntry::isReadable(const std::string & path) -{return (access(path.c_str(), 0x4) == 0);} - -bool CDirEntry::isWritable(const std::string & path) -{return (access(path.c_str(), 0x2) == 0);} - -std::string CDirEntry::baseName(const std::string & path) -{ - std::string::size_type start = path.find_last_of(Separator); -#ifdef WIN32 // WIN32 also understands '/' as the separator. - - if (start == std::string::npos) - start = path.find_last_of("/"); - -#endif - - if (start == std::string::npos) start = 0; - else start++; // We do not want the separator. - - std::string::size_type end = path.find_last_of("."); - - if (end == std::string::npos || end < start) - end = path.length(); - - return path.substr(start, end - start); -} - -std::string CDirEntry::fileName(const std::string & path) -{ - std::string::size_type start = path.find_last_of(Separator); -#ifdef WIN32 // WIN32 also understands '/' as the separator. - - if (start == std::string::npos) - start = path.find_last_of("/"); - -#endif - - if (start == std::string::npos) start = 0; - else start++; // We do not want the separator. - - return path.substr(start); -} - -std::string CDirEntry::dirName(const std::string & path) -{ - if (path == "") return path; - -#ifdef WIN32 // WIN32 also understands '/' as the separator. - std::string::size_type end = path.find_last_of(Separator + "/"); -#else - std::string::size_type end = path.find_last_of(Separator); -#endif - - if (end == path.length() - 1) - { -#ifdef WIN32 // WIN32 also understands '/' as the separator. - end = path.find_last_of(Separator + "/", end); -#else - end = path.find_last_of(Separator, end); -#endif - } - - if (end == std::string::npos) return ""; - - return path.substr(0, end); -} - -std::string CDirEntry::suffix(const std::string & path) -{ - std::string::size_type start = path.find_last_of(Separator); -#ifdef WIN32 // WIN32 also understands '/' as the separator. - - if (start == std::string::npos) - start = path.find_last_of("/"); - -#endif - - if (start == std::string::npos) start = 0; - else start++; // We do not want the separator. - - std::string::size_type end = path.find_last_of("."); - - if (end == std::string::npos || end < start) - return ""; - else - return path.substr(end); -} - -bool CDirEntry::createDir(const std::string & dir, - const std::string & parent) -{ - std::string Dir; - - if (parent != "") Dir = parent + Separator; - - Dir += dir; - - // Check whether the directory already exists and is writable. - if (isDir(Dir) && isWritable(Dir)) return true; - - // Check whether the parent directory exists and is writable. - if (!parent.empty() && (!isDir(parent) || !isWritable(parent))) return false; - - Dir = normalize(Dir); - - // ensure we have parent - std::string actualParent = dirName(Dir); - - if (!actualParent.empty() && (!exist(actualParent))) - createDir(actualParent); - -#ifdef WIN32 - return (mkdir(Dir.c_str()) == 0); -#else - return (mkdir(Dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0); -#endif -} - -std::string CDirEntry::createTmpName(const std::string & dir, - const std::string & suffix) -{ - std::string RandomName; - - do - { - RandomName = dir + Separator; - unsigned int Char; - - for (size_t i = 0; i < 8; i++) - { - Char = int((rand()/double(RAND_MAX))*35.0); - - if (Char < 10) - RandomName += '0' + Char; - else - RandomName += 'a' - 10 + Char; - } - - RandomName += suffix; - } - while (exist(RandomName)); - - return RandomName; -} - -bool CDirEntry::move(const std::string & from, - const std::string & to) -{ - if (!isFile(from)) return false; - - std::string To = to; - - // Check whether To is a directory and append the - // filename of from - if (isDir(To)) - To += Separator + fileName(from); - - if (isDir(To)) return false; - -#ifdef WIN32 - - // The target must not exist under WIN32 for rename to succeed. - if (exist(To) && !remove(To)) - return false; - -#endif // WIN32 - - bool success = - (::rename(from.c_str(), To.c_str()) == 0); - - if (!success) - { - { - std::ifstream in(from.c_str()); - std::ofstream out(To.c_str()); - - out << in.rdbuf(); - - success = out.good(); - } - - remove(from); - } - - return success; -} - -bool CDirEntry::remove(const std::string & path) -{ - if (isDir(path)) - return (rmdir(path.c_str()) == 0); - else if (isFile(path)) -#ifdef WIN32 - return (::remove(path.c_str()) == 0); - -#else - return (::remove(path.c_str()) == 0); -#endif - - return false; -} - -bool CDirEntry::removeFiles(const std::string & pattern, - const std::string & path) -{ - bool success = true; - std::vector< std::string > PatternList; - - PatternList = compilePattern(pattern); - -#ifdef WIN32 - - // We want the same pattern matching behaviour for all platforms. - // Therefore, we do not use the MS provided one and list all files instead. - std::string FilePattern = path + "\\*"; - - // Open directory stream and try read info about first entry - struct _finddata_t Entry; - intptr_t hList = _findfirst(FilePattern.c_str(), &Entry); - - if (hList == -1) return success; - - do - { - std::string Utf8 = Entry.name; - - if (match(Utf8, PatternList)) - { - if (Entry.attrib | _A_NORMAL) - { -#ifdef WIN32 - - if (::remove((path + Separator + Utf8).c_str()) != 0) success = false; - -#else - - if (::remove((path + Separator + Utf8).c_str()) != 0) success = false; - -#endif - } - else - { - if (rmdir((path + Separator + Utf8).c_str()) != 0) success = false; - } - } - } - while (_findnext(hList, &Entry) == 0); - - _findclose(hList); - -#else - - DIR * pDir = opendir(path.c_str()); - - if (!pDir) return false; - - struct dirent * pEntry; - - while ((pEntry = readdir(pDir)) != NULL) - { - std::string Utf8 = pEntry->d_name; - - if (match(Utf8, PatternList)) - { - if (isDir(Utf8)) - { - if (::rmdir((path + Separator + Utf8).c_str()) != 0) - success = false; - } - else - { - if (::remove((path + Separator + Utf8).c_str()) != 0) - success = false; - } - } - } - - closedir(pDir); - -#endif // WIN32 - - return success; -} - -std::vector< std::string > CDirEntry::compilePattern(const std::string & pattern) -{ - std::string::size_type pos = 0; - std::string::size_type start = 0; - std::string::size_type end = 0; - std::vector< std::string > PatternList; - - while (pos != std::string::npos) - { - start = pos; - pos = pattern.find_first_of("*?", pos); - - end = std::min(pos, pattern.length()); - - if (start != end) - PatternList.push_back(pattern.substr(start, end - start)); - else - { - PatternList.push_back(pattern.substr(start, 1)); - pos++; - } - }; - - return PatternList; -} - -bool CDirEntry::match(const std::string & name, - const std::vector< std::string > & patternList) -{ - std::vector< std::string >::const_iterator it = patternList.begin(); - std::vector< std::string >::const_iterator end = patternList.end(); - std::string::size_type at = 0; - std::string::size_type after = 0; - - bool Match = true; - - while (it != end && Match) - Match = matchInternal(name, *it++, at, after); - - return Match; -} - -bool CDirEntry::isRelativePath(const std::string & path) -{ -#ifdef WIN32 - std::string Path = normalize(path); - - if (Path.length() < 2) - return true; - - if (Path[1] == ':') - return false; - - if (Path[0] == '/' && Path[1] == '/') - return false; - - return true; -#else - return (path.length() < 1 || path[0] != '/'); -#endif -} - -bool CDirEntry::makePathRelative(std::string & absolutePath, - const std::string & relativeTo) -{ - if (isRelativePath(absolutePath) || - isRelativePath(relativeTo)) return false; // Nothing can be done. - - std:: string RelativeTo = normalize(relativeTo); - - if (isFile(RelativeTo)) RelativeTo = dirName(RelativeTo); - - if (!isDir(RelativeTo)) return false; - - absolutePath = normalize(absolutePath); - - size_t i, imax = std::min(absolutePath.length(), RelativeTo.length()); - - for (i = 0; i < imax; i++) - if (absolutePath[i] != RelativeTo[i]) break; - - // We need to retract to the beginning of the current directory. - if (i != imax) - i = absolutePath.find_last_of('/', i) + 1; - -#ifdef WIN32 - - if (i == 0) return false; // A different drive letter we cannot do anything - -#endif - - RelativeTo = RelativeTo.substr(i); - - std::string relativePath; - - while (RelativeTo != "") - { - relativePath += "../"; - RelativeTo = dirName(RelativeTo); - } - - if (relativePath != "") - absolutePath = relativePath + absolutePath.substr(i); - else - absolutePath = absolutePath.substr(i + 1); - - return true; -} - -bool CDirEntry::makePathAbsolute(std::string & relativePath, - const std::string & absoluteTo) -{ - if (!isRelativePath(relativePath) || - isRelativePath(absoluteTo)) return false; // Nothing can be done. - - std:: string AbsoluteTo = normalize(absoluteTo); - - if (isFile(AbsoluteTo)) AbsoluteTo = dirName(AbsoluteTo); - - if (!isDir(AbsoluteTo)) return false; - - relativePath = normalize(relativePath); - - while (!relativePath.compare(0, 3, "../")) - { - AbsoluteTo = dirName(AbsoluteTo); - relativePath = relativePath.substr(3); - } - - relativePath = AbsoluteTo + "/" + relativePath; - - return true; -} - -bool CDirEntry::matchInternal(const std::string & name, - const std::string pattern, - std::string::size_type & at, - std::string::size_type & after) -{ - bool Match = true; - - switch (pattern[0]) - { - case '*': - - if (at != std::string::npos) - { - after = at; - at = std::string::npos; - } - - break; - - case '?': - - if (at != std::string::npos) - { - ++at; - Match = (name.length() >= at); - } - else - { - ++after; - Match = (name.length() >= after); - } - - break; - - default: - - if (at != std::string::npos) - { - Match = (name.compare(at, pattern.length(), pattern) == 0); - at += pattern.length(); - } - else - { - at = name.find(pattern, after); - Match = (at != std::string::npos); - at += pattern.length(); - } - - break; - } - - return Match; -} - -std::string CDirEntry::normalize(const std::string & path) -{ - std::string Normalized = path; - -#ifdef WIN32 - // converts all '\' to '/' (only on WIN32) - size_t i, imax; - - for (i = 0, imax = Normalized.length(); i < imax; i++) - if (Normalized[i] == '\\') Normalized[i] = '/'; - -#endif - - // Remove leading './' - while (!Normalized.compare(0, 2, "./")) - Normalized = Normalized.substr(2); - - // Collapse '//' to '/' - std::string::size_type pos = 1; - - while (true) - { - pos = Normalized.find("//", pos); - - if (pos == std::string::npos) break; - - Normalized.erase(pos, 1); - } - - // Collapse '/./' to '/' - pos = 0; - - while (true) - { - pos = Normalized.find("/./", pos); - - if (pos == std::string::npos) break; - - Normalized.erase(pos, 2); - } - - // Collapse '[^/]+/../' to '/' - std::string::size_type start = Normalized.length(); - - while (true) - { - pos = Normalized.rfind("/../", start); - - if (pos == std::string::npos) break; - - start = Normalized.rfind('/', pos - 1); - - if (start == std::string::npos) break; - - if (!Normalized.compare(start, 4, "/../")) continue; - - Normalized.erase(start, pos - start + 3); - start = Normalized.length(); - } - - return Normalized; -} +// Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual +// Properties, Inc., University of Heidelberg, and The University +// of Manchester. +// All rights reserved. + +// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual +// Properties, Inc., EML Research, gGmbH, University of Heidelberg, +// and The University of Manchester. +// All rights reserved. + +// Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual +// Properties, Inc. and EML Research, gGmbH. +// All rights reserved. + +#include +#include +#include + +#ifdef WIN32 +# include +# include +typedef struct _stat STAT; +# define stat _stat +# define S_IFREG _S_IFREG +# define S_IFDIR _S_IFDIR +# define access _access +# define mkdir _mkdir +# define rmdir _rmdir +#else +typedef struct stat STAT; +# include +# include +#endif // WIN32 + +#include "CDirEntry.h" + +#include + +#include + +using namespace zipper; + +#ifdef WIN32 +const std::string CDirEntry::Separator = "\\"; +#else +const std::string CDirEntry::Separator = "/"; +#endif + +bool CDirEntry::isFile(const std::string & path) +{ + STAT st; + + if (stat(path.c_str(), & st) == -1) return false; + +#ifdef WIN32 + return ((st.st_mode & S_IFREG) == S_IFREG); +#else + return S_ISREG(st.st_mode); +#endif +} + +bool CDirEntry::isDir(const std::string & path) +{ + STAT st; + + if (stat(path.c_str(), & st) == -1) return false; + +#ifdef WIN32 + return ((st.st_mode & S_IFDIR) == S_IFDIR); +#else + return S_ISDIR(st.st_mode); +#endif +} + +bool CDirEntry::exist(const std::string & path) +{ + STAT st; + + if (stat(path.c_str(), & st) == -1) return false; + +#ifdef WIN32 + return ((st.st_mode & S_IFREG) == S_IFREG || + (st.st_mode & S_IFDIR) == S_IFDIR); +#else + return (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)); +#endif +} + +bool CDirEntry::isReadable(const std::string & path) +{return (access(path.c_str(), 0x4) == 0);} + +bool CDirEntry::isWritable(const std::string & path) +{return (access(path.c_str(), 0x2) == 0);} + +std::string CDirEntry::baseName(const std::string & path) +{ + std::string::size_type start = path.find_last_of(Separator); +#ifdef WIN32 // WIN32 also understands '/' as the separator. + + if (start == std::string::npos) + start = path.find_last_of("/"); + +#endif + + if (start == std::string::npos) start = 0; + else start++; // We do not want the separator. + + std::string::size_type end = path.find_last_of("."); + + if (end == std::string::npos || end < start) + end = path.length(); + + return path.substr(start, end - start); +} + +std::string CDirEntry::fileName(const std::string & path) +{ + std::string::size_type start = path.find_last_of(Separator); +#ifdef WIN32 // WIN32 also understands '/' as the separator. + + if (start == std::string::npos) + start = path.find_last_of("/"); + +#endif + + if (start == std::string::npos) start = 0; + else start++; // We do not want the separator. + + return path.substr(start); +} + +std::string CDirEntry::dirName(const std::string & path) +{ + if (path == "") return path; + +#ifdef WIN32 // WIN32 also understands '/' as the separator. + std::string::size_type end = path.find_last_of(Separator + "/"); +#else + std::string::size_type end = path.find_last_of(Separator); +#endif + + if (end == path.length() - 1) + { +#ifdef WIN32 // WIN32 also understands '/' as the separator. + end = path.find_last_of(Separator + "/", end); +#else + end = path.find_last_of(Separator, end); +#endif + } + + if (end == std::string::npos) return ""; + + return path.substr(0, end); +} + +std::string CDirEntry::suffix(const std::string & path) +{ + std::string::size_type start = path.find_last_of(Separator); +#ifdef WIN32 // WIN32 also understands '/' as the separator. + + if (start == std::string::npos) + start = path.find_last_of("/"); + +#endif + + if (start == std::string::npos) start = 0; + else start++; // We do not want the separator. + + std::string::size_type end = path.find_last_of("."); + + if (end == std::string::npos || end < start) + return ""; + else + return path.substr(end); +} + +bool CDirEntry::createDir(const std::string & dir, + const std::string & parent) +{ + std::string Dir; + + if (parent != "") Dir = parent + Separator; + + Dir += dir; + + // Check whether the directory already exists and is writable. + if (isDir(Dir) && isWritable(Dir)) return true; + + // Check whether the parent directory exists and is writable. + if (!parent.empty() && (!isDir(parent) || !isWritable(parent))) return false; + + Dir = normalize(Dir); + + // ensure we have parent + std::string actualParent = dirName(Dir); + + if (!actualParent.empty() && (!exist(actualParent))) + createDir(actualParent); + +#ifdef WIN32 + return (mkdir(Dir.c_str()) == 0); +#else + return (mkdir(Dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0); +#endif +} + +std::string CDirEntry::createTmpName(const std::string & dir, + const std::string & suffix) +{ + std::string RandomName; + + do + { + RandomName = dir + Separator; + unsigned int Char; + + for (size_t i = 0; i < 8; i++) + { + Char = int((rand()/double(RAND_MAX))*35.0); + + if (Char < 10) + RandomName += '0' + Char; + else + RandomName += 'a' - 10 + Char; + } + + RandomName += suffix; + } + while (exist(RandomName)); + + return RandomName; +} + +bool CDirEntry::move(const std::string & from, + const std::string & to) +{ + if (!isFile(from)) return false; + + std::string To = to; + + // Check whether To is a directory and append the + // filename of from + if (isDir(To)) + To += Separator + fileName(from); + + if (isDir(To)) return false; + +#ifdef WIN32 + + // The target must not exist under WIN32 for rename to succeed. + if (exist(To) && !remove(To)) + return false; + +#endif // WIN32 + + bool success = + (::rename(from.c_str(), To.c_str()) == 0); + + if (!success) + { + { + std::ifstream in(from.c_str()); + std::ofstream out(To.c_str()); + + out << in.rdbuf(); + + success = out.good(); + } + + remove(from); + } + + return success; +} + +bool CDirEntry::remove(const std::string & path) +{ + if (isDir(path)) + return (rmdir(path.c_str()) == 0); + else if (isFile(path)) +#ifdef WIN32 + return (::remove(path.c_str()) == 0); + +#else + return (::remove(path.c_str()) == 0); +#endif + + return false; +} + +bool CDirEntry::removeFiles(const std::string & pattern, + const std::string & path) +{ + bool success = true; + std::vector< std::string > PatternList; + + PatternList = compilePattern(pattern); + +#ifdef WIN32 + + // We want the same pattern matching behaviour for all platforms. + // Therefore, we do not use the MS provided one and list all files instead. + std::string FilePattern = path + "\\*"; + + // Open directory stream and try read info about first entry + struct _finddata_t Entry; + intptr_t hList = _findfirst(FilePattern.c_str(), &Entry); + + if (hList == -1) return success; + + do + { + std::string Utf8 = Entry.name; + + if (match(Utf8, PatternList)) + { + if (Entry.attrib | _A_NORMAL) + { +#ifdef WIN32 + + if (::remove((path + Separator + Utf8).c_str()) != 0) success = false; + +#else + + if (::remove((path + Separator + Utf8).c_str()) != 0) success = false; + +#endif + } + else + { + if (rmdir((path + Separator + Utf8).c_str()) != 0) success = false; + } + } + } + while (_findnext(hList, &Entry) == 0); + + _findclose(hList); + +#else + + DIR * pDir = opendir(path.c_str()); + + if (!pDir) return false; + + struct dirent * pEntry; + + while ((pEntry = readdir(pDir)) != NULL) + { + std::string Utf8 = pEntry->d_name; + + if (match(Utf8, PatternList)) + { + if (isDir(Utf8)) + { + if (::rmdir((path + Separator + Utf8).c_str()) != 0) + success = false; + } + else + { + if (::remove((path + Separator + Utf8).c_str()) != 0) + success = false; + } + } + } + + closedir(pDir); + +#endif // WIN32 + + return success; +} + +std::vector< std::string > CDirEntry::compilePattern(const std::string & pattern) +{ + std::string::size_type pos = 0; + std::string::size_type start = 0; + std::string::size_type end = 0; + std::vector< std::string > PatternList; + + while (pos != std::string::npos) + { + start = pos; + pos = pattern.find_first_of("*?", pos); + + end = std::min(pos, pattern.length()); + + if (start != end) + PatternList.push_back(pattern.substr(start, end - start)); + else + { + PatternList.push_back(pattern.substr(start, 1)); + pos++; + } + }; + + return PatternList; +} + +bool CDirEntry::match(const std::string & name, + const std::vector< std::string > & patternList) +{ + std::vector< std::string >::const_iterator it = patternList.begin(); + std::vector< std::string >::const_iterator end = patternList.end(); + std::string::size_type at = 0; + std::string::size_type after = 0; + + bool Match = true; + + while (it != end && Match) + Match = matchInternal(name, *it++, at, after); + + return Match; +} + +bool CDirEntry::isRelativePath(const std::string & path) +{ +#ifdef WIN32 + std::string Path = normalize(path); + + if (Path.length() < 2) + return true; + + if (Path[1] == ':') + return false; + + if (Path[0] == '/' && Path[1] == '/') + return false; + + return true; +#else + return (path.length() < 1 || path[0] != '/'); +#endif +} + +bool CDirEntry::makePathRelative(std::string & absolutePath, + const std::string & relativeTo) +{ + if (isRelativePath(absolutePath) || + isRelativePath(relativeTo)) return false; // Nothing can be done. + + std:: string RelativeTo = normalize(relativeTo); + + if (isFile(RelativeTo)) RelativeTo = dirName(RelativeTo); + + if (!isDir(RelativeTo)) return false; + + absolutePath = normalize(absolutePath); + + size_t i, imax = std::min(absolutePath.length(), RelativeTo.length()); + + for (i = 0; i < imax; i++) + if (absolutePath[i] != RelativeTo[i]) break; + + // We need to retract to the beginning of the current directory. + if (i != imax) + i = absolutePath.find_last_of('/', i) + 1; + +#ifdef WIN32 + + if (i == 0) return false; // A different drive letter we cannot do anything + +#endif + + RelativeTo = RelativeTo.substr(i); + + std::string relativePath; + + while (RelativeTo != "") + { + relativePath += "../"; + RelativeTo = dirName(RelativeTo); + } + + if (relativePath != "") + absolutePath = relativePath + absolutePath.substr(i); + else + absolutePath = absolutePath.substr(i + 1); + + return true; +} + +bool CDirEntry::makePathAbsolute(std::string & relativePath, + const std::string & absoluteTo) +{ + if (!isRelativePath(relativePath) || + isRelativePath(absoluteTo)) return false; // Nothing can be done. + + std:: string AbsoluteTo = normalize(absoluteTo); + + if (isFile(AbsoluteTo)) AbsoluteTo = dirName(AbsoluteTo); + + if (!isDir(AbsoluteTo)) return false; + + relativePath = normalize(relativePath); + + while (!relativePath.compare(0, 3, "../")) + { + AbsoluteTo = dirName(AbsoluteTo); + relativePath = relativePath.substr(3); + } + + relativePath = AbsoluteTo + "/" + relativePath; + + return true; +} + +bool CDirEntry::matchInternal(const std::string & name, + const std::string pattern, + std::string::size_type & at, + std::string::size_type & after) +{ + bool Match = true; + + switch (pattern[0]) + { + case '*': + + if (at != std::string::npos) + { + after = at; + at = std::string::npos; + } + + break; + + case '?': + + if (at != std::string::npos) + { + ++at; + Match = (name.length() >= at); + } + else + { + ++after; + Match = (name.length() >= after); + } + + break; + + default: + + if (at != std::string::npos) + { + Match = (name.compare(at, pattern.length(), pattern) == 0); + at += pattern.length(); + } + else + { + at = name.find(pattern, after); + Match = (at != std::string::npos); + at += pattern.length(); + } + + break; + } + + return Match; +} + +std::string CDirEntry::normalize(const std::string & path) +{ + std::string Normalized = path; + +#ifdef WIN32 + // converts all '\' to '/' (only on WIN32) + size_t i, imax; + + for (i = 0, imax = Normalized.length(); i < imax; i++) + if (Normalized[i] == '\\') Normalized[i] = '/'; + +#endif + + // Remove leading './' + while (!Normalized.compare(0, 2, "./")) + Normalized = Normalized.substr(2); + + // Collapse '//' to '/' + std::string::size_type pos = 1; + + while (true) + { + pos = Normalized.find("//", pos); + + if (pos == std::string::npos) break; + + Normalized.erase(pos, 1); + } + + // Collapse '/./' to '/' + pos = 0; + + while (true) + { + pos = Normalized.find("/./", pos); + + if (pos == std::string::npos) break; + + Normalized.erase(pos, 2); + } + + // Collapse '[^/]+/../' to '/' + std::string::size_type start = Normalized.length(); + + while (true) + { + pos = Normalized.rfind("/../", start); + + if (pos == std::string::npos) break; + + start = Normalized.rfind('/', pos - 1); + + if (start == std::string::npos) break; + + if (!Normalized.compare(start, 4, "/../")) continue; + + Normalized.erase(start, pos - start + 3); + start = Normalized.length(); + } + + return Normalized; +} diff --git a/libs/minizip/source/aes/Makefile b/libs/minizip/source/aes/Makefile index 5340a2d9..d7e3234b 100644 --- a/libs/minizip/source/aes/Makefile +++ b/libs/minizip/source/aes/Makefile @@ -1,19 +1,19 @@ -CC=cc -CFLAGS=-O -DHAVE_AES -OBJS=aescrypt.o aeskey.o aestab.o entropy.o fileenc.o hmac.o prng.o pwd2key.o sha1.o -ARFLAGS=rv - -.c.o: - $(CC) -c $(CFLAGS) $*.c - -libaes.a: $(OBJS) - $(ECHO) $(AR) $(ARFLAGS) ../libaes.a $? - $(AR) $(ARFLAGS) ../libaes.a $? - $(RANLIB) ../libaes.a - -all: libaes.a - -.PHONY: clean - -clean: +CC=cc +CFLAGS=-O -DHAVE_AES +OBJS=aescrypt.o aeskey.o aestab.o entropy.o fileenc.o hmac.o prng.o pwd2key.o sha1.o +ARFLAGS=rv + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +libaes.a: $(OBJS) + $(ECHO) $(AR) $(ARFLAGS) ../libaes.a $? + $(AR) $(ARFLAGS) ../libaes.a $? + $(RANLIB) ../libaes.a + +all: libaes.a + +.PHONY: clean + +clean: rm *.o *.a \ No newline at end of file diff --git a/libs/minizip/source/aes/aes.h b/libs/minizip/source/aes/aes.h index 40927fb7..44682c39 100644 --- a/libs/minizip/source/aes/aes.h +++ b/libs/minizip/source/aes/aes.h @@ -1,198 +1,198 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the definitions required to use AES in C. See aesopt.h - for optimisation details. -*/ - -#ifndef _AES_H -#define _AES_H - -#include - -/* This include is used to find 8 & 32 bit unsigned integer types */ -#include "brg_types.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define AES_128 /* if a fast 128 bit key scheduler is needed */ -#define AES_192 /* if a fast 192 bit key scheduler is needed */ -#define AES_256 /* if a fast 256 bit key scheduler is needed */ -#define AES_VAR /* if variable key size scheduler is needed */ -#define AES_MODES /* if support is needed for modes */ - -/* The following must also be set in assembler files if being used */ - -#define AES_ENCRYPT /* if support for encryption is needed */ -#define AES_DECRYPT /* if support for decryption is needed */ -#define AES_REV_DKS /* define to reverse decryption key schedule */ - -#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ -#define N_COLS 4 /* the number of columns in the state */ - -/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ -/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ -/* or 44, 52 or 60 32-bit words. */ - -#if defined( AES_VAR ) || defined( AES_256 ) -#define KS_LENGTH 60 -#elif defined( AES_192 ) -#define KS_LENGTH 52 -#else -#define KS_LENGTH 44 -#endif - -#define AES_RETURN INT_RETURN - -/* the character array 'inf' in the following structures is used */ -/* to hold AES context information. This AES code uses cx->inf.b[0] */ -/* to hold the number of rounds multiplied by 16. The other three */ -/* elements can be used by code that implements additional modes */ - -typedef union -{ uint_32t l; - uint_8t b[4]; -} aes_inf; - -typedef struct -{ uint_32t ks[KS_LENGTH]; - aes_inf inf; -} aes_encrypt_ctx; - -typedef struct -{ uint_32t ks[KS_LENGTH]; - aes_inf inf; -} aes_decrypt_ctx; - -/* This routine must be called before first use if non-static */ -/* tables are being used */ - -AES_RETURN aes_init(void); - -/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ -/* those in the range 128 <= key_len <= 256 are given in bits */ - -#if defined( AES_ENCRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); -#endif - -AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); - -#endif - -#if defined( AES_DECRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); -#endif - -AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); - -#endif - -#if defined( AES_MODES ) - -/* Multiple calls to the following subroutines for multiple block */ -/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ -/* long messages incremantally provided that the context AND the iv */ -/* are preserved between all such calls. For the ECB and CBC modes */ -/* each individual call within a series of incremental calls must */ -/* process only full blocks (i.e. len must be a multiple of 16) but */ -/* the CFB, OFB and CTR mode calls can handle multiple incremental */ -/* calls of any length. Each mode is reset when a new AES key is */ -/* set but ECB and CBC operations can be reset without setting a */ -/* new key by setting a new IV value. To reset CFB, OFB and CTR */ -/* without setting the key, aes_mode_reset() must be called and the */ -/* IV must be set. NOTE: All these calls update the IV on exit so */ -/* this has to be reset if a new operation with the same IV as the */ -/* previous one is required (or decryption follows encryption with */ -/* the same IV array). */ - -AES_RETURN aes_test_alignment_detection(unsigned int n); - -AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -#define aes_ofb_encrypt aes_ofb_crypt -#define aes_ofb_decrypt aes_ofb_crypt - -AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -typedef void cbuf_inc(unsigned char *cbuf); - -#define aes_ctr_encrypt aes_ctr_crypt -#define aes_ctr_decrypt aes_ctr_crypt - -AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); - -#endif - -#if defined(__cplusplus) -} -#endif - -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. +*/ + +#ifndef _AES_H +#define _AES_H + +#include + +/* This include is used to find 8 & 32 bit unsigned integer types */ +#include "brg_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define AES_128 /* if a fast 128 bit key scheduler is needed */ +#define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +#define AES_VAR /* if variable key size scheduler is needed */ +#define AES_MODES /* if support is needed for modes */ + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ +#define AES_REV_DKS /* define to reverse decryption key schedule */ + +#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ +#define N_COLS 4 /* the number of columns in the state */ + +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ + +#if defined( AES_VAR ) || defined( AES_256 ) +#define KS_LENGTH 60 +#elif defined( AES_192 ) +#define KS_LENGTH 52 +#else +#define KS_LENGTH 44 +#endif + +#define AES_RETURN INT_RETURN + +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ + +typedef union +{ uint_32t l; + uint_8t b[4]; +} aes_inf; + +typedef struct +{ uint_32t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +typedef struct +{ uint_32t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +AES_RETURN aes_init(void); + +/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ +/* those in the range 128 <= key_len <= 256 are given in bits */ + +#if defined( AES_ENCRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); +#endif + +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); + +#endif + +#if defined( AES_DECRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); + +#endif + +#if defined( AES_MODES ) + +/* Multiple calls to the following subroutines for multiple block */ +/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ +/* long messages incremantally provided that the context AND the iv */ +/* are preserved between all such calls. For the ECB and CBC modes */ +/* each individual call within a series of incremental calls must */ +/* process only full blocks (i.e. len must be a multiple of 16) but */ +/* the CFB, OFB and CTR mode calls can handle multiple incremental */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB and CBC operations can be reset without setting a */ +/* new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* without setting the key, aes_mode_reset() must be called and the */ +/* IV must be set. NOTE: All these calls update the IV on exit so */ +/* this has to be reset if a new operation with the same IV as the */ +/* previous one is required (or decryption follows encryption with */ +/* the same IV array). */ + +AES_RETURN aes_test_alignment_detection(unsigned int n); + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +#define aes_ofb_encrypt aes_ofb_crypt +#define aes_ofb_decrypt aes_ofb_crypt + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +typedef void cbuf_inc(unsigned char *cbuf); + +#define aes_ctr_encrypt aes_ctr_crypt +#define aes_ctr_decrypt aes_ctr_crypt + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); + +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/aes_via_ace.h b/libs/minizip/source/aes/aes_via_ace.h index bb7a9cf4..cb2aa1ba 100644 --- a/libs/minizip/source/aes/aes_via_ace.h +++ b/libs/minizip/source/aes/aes_via_ace.h @@ -1,541 +1,541 @@ -/* -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#ifndef AES_VIA_ACE_H -#define AES_VIA_ACE_H - -#if defined( _MSC_VER ) -# define INLINE __inline -#elif defined( __GNUC__ ) -# define INLINE static inline -#else -# error VIA ACE requires Microsoft or GNU C -#endif - -#define NEH_GENERATE 1 -#define NEH_LOAD 2 -#define NEH_HYBRID 3 - -#define MAX_READ_ATTEMPTS 1000 - -/* VIA Nehemiah RNG and ACE Feature Mask Values */ - -#define NEH_CPU_IS_VIA 0x00000001 -#define NEH_CPU_READ 0x00000010 -#define NEH_CPU_MASK 0x00000011 - -#define NEH_RNG_PRESENT 0x00000004 -#define NEH_RNG_ENABLED 0x00000008 -#define NEH_ACE_PRESENT 0x00000040 -#define NEH_ACE_ENABLED 0x00000080 -#define NEH_RNG_FLAGS (NEH_RNG_PRESENT | NEH_RNG_ENABLED) -#define NEH_ACE_FLAGS (NEH_ACE_PRESENT | NEH_ACE_ENABLED) -#define NEH_FLAGS_MASK (NEH_RNG_FLAGS | NEH_ACE_FLAGS) - -/* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values */ - -#define NEH_GEN_KEY 0x00000000 /* generate key schedule */ -#define NEH_LOAD_KEY 0x00000080 /* load schedule from memory */ -#define NEH_ENCRYPT 0x00000000 /* encryption */ -#define NEH_DECRYPT 0x00000200 /* decryption */ -#define NEH_KEY128 0x00000000+0x0a /* 128 bit key */ -#define NEH_KEY192 0x00000400+0x0c /* 192 bit key */ -#define NEH_KEY256 0x00000800+0x0e /* 256 bit key */ - -#define NEH_ENC_GEN (NEH_ENCRYPT | NEH_GEN_KEY) -#define NEH_DEC_GEN (NEH_DECRYPT | NEH_GEN_KEY) -#define NEH_ENC_LOAD (NEH_ENCRYPT | NEH_LOAD_KEY) -#define NEH_DEC_LOAD (NEH_DECRYPT | NEH_LOAD_KEY) - -#define NEH_ENC_GEN_DATA {\ - NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ - NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\ - NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 } - -#define NEH_ENC_LOAD_DATA {\ - NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\ - NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ - NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } - -#define NEH_ENC_HYBRID_DATA {\ - NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ - NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ - NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } - -#define NEH_DEC_GEN_DATA {\ - NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ - NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\ - NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 } - -#define NEH_DEC_LOAD_DATA {\ - NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\ - NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ - NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } - -#define NEH_DEC_HYBRID_DATA {\ - NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ - NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ - NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } - -#define neh_enc_gen_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ - (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256)) - -#define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) : \ - (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) - -#define neh_enc_hybrid_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ - (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) - -#define neh_dec_gen_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ - (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256)) - -#define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) : \ - (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) - -#define neh_dec_hybrid_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ - (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) - -#if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) -#define aligned_auto(type, name, no, stride) __declspec(align(stride)) type name[no] -#else -#define aligned_auto(type, name, no, stride) \ - unsigned char _##name[no * sizeof(type) + stride]; \ - type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride)) -#endif - -#if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) -#define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no] -#elif defined( __GNUC__ ) -#define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride))) -#else -#define aligned_array(type, name, no, stride) type name[no] -#endif - -/* VIA ACE codeword */ - -static unsigned char via_flags = 0; - -#if defined ( _MSC_VER ) && ( _MSC_VER > 800 ) - -#define NEH_REKEY __asm pushfd __asm popfd -#define NEH_AES __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7 -#define NEH_ECB NEH_AES __asm _emit 0xc8 -#define NEH_CBC NEH_AES __asm _emit 0xd0 -#define NEH_CFB NEH_AES __asm _emit 0xe0 -#define NEH_OFB NEH_AES __asm _emit 0xe8 -#define NEH_RNG __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0 - -INLINE int has_cpuid(void) -{ char ret_value; - __asm - { pushfd /* save EFLAGS register */ - mov eax,[esp] /* copy it to eax */ - mov edx,0x00200000 /* CPUID bit position */ - xor eax,edx /* toggle the CPUID bit */ - push eax /* attempt to set EFLAGS to */ - popfd /* the new value */ - pushfd /* get the new EFLAGS value */ - pop eax /* into eax */ - xor eax,[esp] /* xor with original value */ - and eax,edx /* has CPUID bit changed? */ - setne al /* set to 1 if we have been */ - mov ret_value,al /* able to change it */ - popfd /* restore original EFLAGS */ - } - return (int)ret_value; -} - -INLINE int is_via_cpu(void) -{ char ret_value; - __asm - { push ebx - xor eax,eax /* use CPUID to get vendor */ - cpuid /* identity string */ - xor eax,eax /* is it "CentaurHauls" ? */ - sub ebx,0x746e6543 /* 'Cent' */ - or eax,ebx - sub edx,0x48727561 /* 'aurH' */ - or eax,edx - sub ecx,0x736c7561 /* 'auls' */ - or eax,ecx - sete al /* set to 1 if it is VIA ID */ - mov dl,NEH_CPU_READ /* mark CPU type as read */ - or dl,al /* & store result in flags */ - mov [via_flags],dl /* set VIA detected flag */ - mov ret_value,al /* able to change it */ - pop ebx - } - return (int)ret_value; -} - -INLINE int read_via_flags(void) -{ char ret_value = 0; - __asm - { mov eax,0xC0000000 /* Centaur extended CPUID */ - cpuid - mov edx,0xc0000001 /* >= 0xc0000001 if support */ - cmp eax,edx /* for VIA extended feature */ - jnae no_rng /* flags is available */ - mov eax,edx /* read Centaur extended */ - cpuid /* feature flags */ - mov eax,NEH_FLAGS_MASK /* mask out and save */ - and eax,edx /* the RNG and ACE flags */ - or [via_flags],al /* present & enabled flags */ - mov ret_value,al /* able to change it */ -no_rng: - } - return (int)ret_value; -} - -INLINE unsigned int via_rng_in(void *buf) -{ char ret_value = 0x1f; - __asm - { push edi - mov edi,buf /* input buffer address */ - xor edx,edx /* try to fetch 8 bytes */ - NEH_RNG /* do RNG read operation */ - and ret_value,al /* count of bytes returned */ - pop edi - } - return (int)ret_value; -} - -INLINE void via_ecb_op5( - const void *k, const void *c, const void *s, void *d, int l) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - NEH_ECB - pop ebx - } -} - -INLINE void via_cbc_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - mov eax, (v) - NEH_CBC - pop ebx - } -} - -INLINE void via_cbc_op7( - const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - mov eax, (v) - NEH_CBC - mov esi, eax - mov edi, (w) - movsd - movsd - movsd - movsd - pop ebx - } -} - -INLINE void via_cfb_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - mov eax, (v) - NEH_CFB - pop ebx - } -} - -INLINE void via_cfb_op7( - const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - mov eax, (v) - NEH_CFB - mov esi, eax - mov edi, (w) - movsd - movsd - movsd - movsd - pop ebx - } -} - -INLINE void via_ofb_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ __asm - { push ebx - NEH_REKEY - mov ebx, (k) - mov edx, (c) - mov esi, (s) - mov edi, (d) - mov ecx, (l) - mov eax, (v) - NEH_OFB - pop ebx - } -} - -#elif defined( __GNUC__ ) - -#define NEH_REKEY asm("pushfl\n popfl\n\t") -#define NEH_ECB asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t") -#define NEH_CBC asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t") -#define NEH_CFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t") -#define NEH_OFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t") -#define NEH_RNG asm(".byte 0x0f, 0xa7, 0xc0\n\t"); - -INLINE int has_cpuid(void) -{ int val; - asm("pushfl\n\t"); - asm("movl 0(%esp),%eax\n\t"); - asm("xor $0x00200000,%eax\n\t"); - asm("pushl %eax\n\t"); - asm("popfl\n\t"); - asm("pushfl\n\t"); - asm("popl %eax\n\t"); - asm("xorl 0(%esp),%edx\n\t"); - asm("andl $0x00200000,%eax\n\t"); - asm("movl %%eax,%0\n\t" : "=m" (val)); - asm("popfl\n\t"); - return val ? 1 : 0; -} - -INLINE int is_via_cpu(void) -{ int val; - asm("pushl %ebx\n\t"); - asm("xorl %eax,%eax\n\t"); - asm("cpuid\n\t"); - asm("xorl %eax,%eax\n\t"); - asm("subl $0x746e6543,%ebx\n\t"); - asm("orl %ebx,%eax\n\t"); - asm("subl $0x48727561,%edx\n\t"); - asm("orl %edx,%eax\n\t"); - asm("subl $0x736c7561,%ecx\n\t"); - asm("orl %ecx,%eax\n\t"); - asm("movl %%eax,%0\n\t" : "=m" (val)); - asm("popl %ebx\n\t"); - val = (val ? 0 : 1); - via_flags = (val | NEH_CPU_READ); - return val; -} - -INLINE int read_via_flags(void) -{ unsigned char val; - asm("movl $0xc0000000,%eax\n\t"); - asm("cpuid\n\t"); - asm("movl $0xc0000001,%edx\n\t"); - asm("cmpl %edx,%eax\n\t"); - asm("setae %al\n\t"); - asm("movb %%al,%0\n\t" : "=m" (val)); - if(!val) return 0; - asm("movl $0xc0000001,%eax\n\t"); - asm("cpuid\n\t"); - asm("movb %%dl,%0\n\t" : "=m" (val)); - val &= NEH_FLAGS_MASK; - via_flags |= val; - return (int) val; -} - -INLINE int via_rng_in(void *buf) -{ int val; - asm("pushl %edi\n\t"); - asm("movl %0,%%edi\n\t" : : "m" (buf)); - asm("xorl %edx,%edx\n\t"); - NEH_RNG - asm("andl $0x0000001f,%eax\n\t"); - asm("movl %%eax,%0\n\t" : "=m" (val)); - asm("popl %edi\n\t"); - return val; -} - -INLINE volatile void via_ecb_op5( - const void *k, const void *c, const void *s, void *d, int l) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - NEH_ECB; - asm("popl %ebx\n\t"); -} - -INLINE volatile void via_cbc_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - asm("movl %0, %%eax\n\t" : : "m" (v)); - NEH_CBC; - asm("popl %ebx\n\t"); -} - -INLINE volatile void via_cbc_op7( - const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - asm("movl %0, %%eax\n\t" : : "m" (v)); - NEH_CBC; - asm("movl %eax,%esi\n\t"); - asm("movl %0, %%edi\n\t" : : "m" (w)); - asm("movsl; movsl; movsl; movsl\n\t"); - asm("popl %ebx\n\t"); -} - -INLINE volatile void via_cfb_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - asm("movl %0, %%eax\n\t" : : "m" (v)); - NEH_CFB; - asm("popl %ebx\n\t"); -} - -INLINE volatile void via_cfb_op7( - const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - asm("movl %0, %%eax\n\t" : : "m" (v)); - NEH_CFB; - asm("movl %eax,%esi\n\t"); - asm("movl %0, %%edi\n\t" : : "m" (w)); - asm("movsl; movsl; movsl; movsl\n\t"); - asm("popl %ebx\n\t"); -} - -INLINE volatile void via_ofb_op6( - const void *k, const void *c, const void *s, void *d, int l, void *v) -{ - asm("pushl %ebx\n\t"); - NEH_REKEY; - asm("movl %0, %%ebx\n\t" : : "m" (k)); - asm("movl %0, %%edx\n\t" : : "m" (c)); - asm("movl %0, %%esi\n\t" : : "m" (s)); - asm("movl %0, %%edi\n\t" : : "m" (d)); - asm("movl %0, %%ecx\n\t" : : "m" (l)); - asm("movl %0, %%eax\n\t" : : "m" (v)); - NEH_OFB; - asm("popl %ebx\n\t"); -} - -#else -#error VIA ACE is not available with this compiler -#endif - -INLINE int via_ace_test(void) -{ - return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS); -} - -#define VIA_ACE_AVAILABLE (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS) \ - || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test()) - -INLINE int via_rng_test(void) -{ - return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS); -} - -#define VIA_RNG_AVAILABLE (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS) \ - || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test()) - -INLINE int read_via_rng(void *buf, int count) -{ int nbr, max_reads, lcnt = count; - unsigned char *p, *q; - aligned_auto(unsigned char, bp, 64, 16); - - if(!VIA_RNG_AVAILABLE) - return 0; - - do - { - max_reads = MAX_READ_ATTEMPTS; - do - nbr = via_rng_in(bp); - while - (nbr == 0 && --max_reads); - - lcnt -= nbr; - p = (unsigned char*)buf; q = bp; - while(nbr--) - *p++ = *q++; - } - while - (lcnt && max_reads); - - return count - lcnt; -} - -#endif +/* +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#ifndef AES_VIA_ACE_H +#define AES_VIA_ACE_H + +#if defined( _MSC_VER ) +# define INLINE __inline +#elif defined( __GNUC__ ) +# define INLINE static inline +#else +# error VIA ACE requires Microsoft or GNU C +#endif + +#define NEH_GENERATE 1 +#define NEH_LOAD 2 +#define NEH_HYBRID 3 + +#define MAX_READ_ATTEMPTS 1000 + +/* VIA Nehemiah RNG and ACE Feature Mask Values */ + +#define NEH_CPU_IS_VIA 0x00000001 +#define NEH_CPU_READ 0x00000010 +#define NEH_CPU_MASK 0x00000011 + +#define NEH_RNG_PRESENT 0x00000004 +#define NEH_RNG_ENABLED 0x00000008 +#define NEH_ACE_PRESENT 0x00000040 +#define NEH_ACE_ENABLED 0x00000080 +#define NEH_RNG_FLAGS (NEH_RNG_PRESENT | NEH_RNG_ENABLED) +#define NEH_ACE_FLAGS (NEH_ACE_PRESENT | NEH_ACE_ENABLED) +#define NEH_FLAGS_MASK (NEH_RNG_FLAGS | NEH_ACE_FLAGS) + +/* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values */ + +#define NEH_GEN_KEY 0x00000000 /* generate key schedule */ +#define NEH_LOAD_KEY 0x00000080 /* load schedule from memory */ +#define NEH_ENCRYPT 0x00000000 /* encryption */ +#define NEH_DECRYPT 0x00000200 /* decryption */ +#define NEH_KEY128 0x00000000+0x0a /* 128 bit key */ +#define NEH_KEY192 0x00000400+0x0c /* 192 bit key */ +#define NEH_KEY256 0x00000800+0x0e /* 256 bit key */ + +#define NEH_ENC_GEN (NEH_ENCRYPT | NEH_GEN_KEY) +#define NEH_DEC_GEN (NEH_DECRYPT | NEH_GEN_KEY) +#define NEH_ENC_LOAD (NEH_ENCRYPT | NEH_LOAD_KEY) +#define NEH_DEC_LOAD (NEH_DECRYPT | NEH_LOAD_KEY) + +#define NEH_ENC_GEN_DATA {\ + NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ + NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\ + NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 } + +#define NEH_ENC_LOAD_DATA {\ + NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\ + NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ + NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } + +#define NEH_ENC_HYBRID_DATA {\ + NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\ + NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\ + NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 } + +#define NEH_DEC_GEN_DATA {\ + NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ + NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\ + NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 } + +#define NEH_DEC_LOAD_DATA {\ + NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\ + NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ + NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } + +#define NEH_DEC_HYBRID_DATA {\ + NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\ + NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\ + NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 } + +#define neh_enc_gen_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ + (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256)) + +#define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) : \ + (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) + +#define neh_enc_hybrid_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \ + (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256)) + +#define neh_dec_gen_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ + (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256)) + +#define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) : \ + (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) + +#define neh_dec_hybrid_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \ + (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256)) + +#if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) +#define aligned_auto(type, name, no, stride) __declspec(align(stride)) type name[no] +#else +#define aligned_auto(type, name, no, stride) \ + unsigned char _##name[no * sizeof(type) + stride]; \ + type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride)) +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER > 1200 ) +#define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no] +#elif defined( __GNUC__ ) +#define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride))) +#else +#define aligned_array(type, name, no, stride) type name[no] +#endif + +/* VIA ACE codeword */ + +static unsigned char via_flags = 0; + +#if defined ( _MSC_VER ) && ( _MSC_VER > 800 ) + +#define NEH_REKEY __asm pushfd __asm popfd +#define NEH_AES __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7 +#define NEH_ECB NEH_AES __asm _emit 0xc8 +#define NEH_CBC NEH_AES __asm _emit 0xd0 +#define NEH_CFB NEH_AES __asm _emit 0xe0 +#define NEH_OFB NEH_AES __asm _emit 0xe8 +#define NEH_RNG __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0 + +INLINE int has_cpuid(void) +{ char ret_value; + __asm + { pushfd /* save EFLAGS register */ + mov eax,[esp] /* copy it to eax */ + mov edx,0x00200000 /* CPUID bit position */ + xor eax,edx /* toggle the CPUID bit */ + push eax /* attempt to set EFLAGS to */ + popfd /* the new value */ + pushfd /* get the new EFLAGS value */ + pop eax /* into eax */ + xor eax,[esp] /* xor with original value */ + and eax,edx /* has CPUID bit changed? */ + setne al /* set to 1 if we have been */ + mov ret_value,al /* able to change it */ + popfd /* restore original EFLAGS */ + } + return (int)ret_value; +} + +INLINE int is_via_cpu(void) +{ char ret_value; + __asm + { push ebx + xor eax,eax /* use CPUID to get vendor */ + cpuid /* identity string */ + xor eax,eax /* is it "CentaurHauls" ? */ + sub ebx,0x746e6543 /* 'Cent' */ + or eax,ebx + sub edx,0x48727561 /* 'aurH' */ + or eax,edx + sub ecx,0x736c7561 /* 'auls' */ + or eax,ecx + sete al /* set to 1 if it is VIA ID */ + mov dl,NEH_CPU_READ /* mark CPU type as read */ + or dl,al /* & store result in flags */ + mov [via_flags],dl /* set VIA detected flag */ + mov ret_value,al /* able to change it */ + pop ebx + } + return (int)ret_value; +} + +INLINE int read_via_flags(void) +{ char ret_value = 0; + __asm + { mov eax,0xC0000000 /* Centaur extended CPUID */ + cpuid + mov edx,0xc0000001 /* >= 0xc0000001 if support */ + cmp eax,edx /* for VIA extended feature */ + jnae no_rng /* flags is available */ + mov eax,edx /* read Centaur extended */ + cpuid /* feature flags */ + mov eax,NEH_FLAGS_MASK /* mask out and save */ + and eax,edx /* the RNG and ACE flags */ + or [via_flags],al /* present & enabled flags */ + mov ret_value,al /* able to change it */ +no_rng: + } + return (int)ret_value; +} + +INLINE unsigned int via_rng_in(void *buf) +{ char ret_value = 0x1f; + __asm + { push edi + mov edi,buf /* input buffer address */ + xor edx,edx /* try to fetch 8 bytes */ + NEH_RNG /* do RNG read operation */ + and ret_value,al /* count of bytes returned */ + pop edi + } + return (int)ret_value; +} + +INLINE void via_ecb_op5( + const void *k, const void *c, const void *s, void *d, int l) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + NEH_ECB + pop ebx + } +} + +INLINE void via_cbc_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + mov eax, (v) + NEH_CBC + pop ebx + } +} + +INLINE void via_cbc_op7( + const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + mov eax, (v) + NEH_CBC + mov esi, eax + mov edi, (w) + movsd + movsd + movsd + movsd + pop ebx + } +} + +INLINE void via_cfb_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + mov eax, (v) + NEH_CFB + pop ebx + } +} + +INLINE void via_cfb_op7( + const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + mov eax, (v) + NEH_CFB + mov esi, eax + mov edi, (w) + movsd + movsd + movsd + movsd + pop ebx + } +} + +INLINE void via_ofb_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ __asm + { push ebx + NEH_REKEY + mov ebx, (k) + mov edx, (c) + mov esi, (s) + mov edi, (d) + mov ecx, (l) + mov eax, (v) + NEH_OFB + pop ebx + } +} + +#elif defined( __GNUC__ ) + +#define NEH_REKEY asm("pushfl\n popfl\n\t") +#define NEH_ECB asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t") +#define NEH_CBC asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t") +#define NEH_CFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t") +#define NEH_OFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t") +#define NEH_RNG asm(".byte 0x0f, 0xa7, 0xc0\n\t"); + +INLINE int has_cpuid(void) +{ int val; + asm("pushfl\n\t"); + asm("movl 0(%esp),%eax\n\t"); + asm("xor $0x00200000,%eax\n\t"); + asm("pushl %eax\n\t"); + asm("popfl\n\t"); + asm("pushfl\n\t"); + asm("popl %eax\n\t"); + asm("xorl 0(%esp),%edx\n\t"); + asm("andl $0x00200000,%eax\n\t"); + asm("movl %%eax,%0\n\t" : "=m" (val)); + asm("popfl\n\t"); + return val ? 1 : 0; +} + +INLINE int is_via_cpu(void) +{ int val; + asm("pushl %ebx\n\t"); + asm("xorl %eax,%eax\n\t"); + asm("cpuid\n\t"); + asm("xorl %eax,%eax\n\t"); + asm("subl $0x746e6543,%ebx\n\t"); + asm("orl %ebx,%eax\n\t"); + asm("subl $0x48727561,%edx\n\t"); + asm("orl %edx,%eax\n\t"); + asm("subl $0x736c7561,%ecx\n\t"); + asm("orl %ecx,%eax\n\t"); + asm("movl %%eax,%0\n\t" : "=m" (val)); + asm("popl %ebx\n\t"); + val = (val ? 0 : 1); + via_flags = (val | NEH_CPU_READ); + return val; +} + +INLINE int read_via_flags(void) +{ unsigned char val; + asm("movl $0xc0000000,%eax\n\t"); + asm("cpuid\n\t"); + asm("movl $0xc0000001,%edx\n\t"); + asm("cmpl %edx,%eax\n\t"); + asm("setae %al\n\t"); + asm("movb %%al,%0\n\t" : "=m" (val)); + if(!val) return 0; + asm("movl $0xc0000001,%eax\n\t"); + asm("cpuid\n\t"); + asm("movb %%dl,%0\n\t" : "=m" (val)); + val &= NEH_FLAGS_MASK; + via_flags |= val; + return (int) val; +} + +INLINE int via_rng_in(void *buf) +{ int val; + asm("pushl %edi\n\t"); + asm("movl %0,%%edi\n\t" : : "m" (buf)); + asm("xorl %edx,%edx\n\t"); + NEH_RNG + asm("andl $0x0000001f,%eax\n\t"); + asm("movl %%eax,%0\n\t" : "=m" (val)); + asm("popl %edi\n\t"); + return val; +} + +INLINE volatile void via_ecb_op5( + const void *k, const void *c, const void *s, void *d, int l) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + NEH_ECB; + asm("popl %ebx\n\t"); +} + +INLINE volatile void via_cbc_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + asm("movl %0, %%eax\n\t" : : "m" (v)); + NEH_CBC; + asm("popl %ebx\n\t"); +} + +INLINE volatile void via_cbc_op7( + const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + asm("movl %0, %%eax\n\t" : : "m" (v)); + NEH_CBC; + asm("movl %eax,%esi\n\t"); + asm("movl %0, %%edi\n\t" : : "m" (w)); + asm("movsl; movsl; movsl; movsl\n\t"); + asm("popl %ebx\n\t"); +} + +INLINE volatile void via_cfb_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + asm("movl %0, %%eax\n\t" : : "m" (v)); + NEH_CFB; + asm("popl %ebx\n\t"); +} + +INLINE volatile void via_cfb_op7( + const void *k, const void *c, const void *s, void *d, int l, void *v, void *w) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + asm("movl %0, %%eax\n\t" : : "m" (v)); + NEH_CFB; + asm("movl %eax,%esi\n\t"); + asm("movl %0, %%edi\n\t" : : "m" (w)); + asm("movsl; movsl; movsl; movsl\n\t"); + asm("popl %ebx\n\t"); +} + +INLINE volatile void via_ofb_op6( + const void *k, const void *c, const void *s, void *d, int l, void *v) +{ + asm("pushl %ebx\n\t"); + NEH_REKEY; + asm("movl %0, %%ebx\n\t" : : "m" (k)); + asm("movl %0, %%edx\n\t" : : "m" (c)); + asm("movl %0, %%esi\n\t" : : "m" (s)); + asm("movl %0, %%edi\n\t" : : "m" (d)); + asm("movl %0, %%ecx\n\t" : : "m" (l)); + asm("movl %0, %%eax\n\t" : : "m" (v)); + NEH_OFB; + asm("popl %ebx\n\t"); +} + +#else +#error VIA ACE is not available with this compiler +#endif + +INLINE int via_ace_test(void) +{ + return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS); +} + +#define VIA_ACE_AVAILABLE (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS) \ + || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test()) + +INLINE int via_rng_test(void) +{ + return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS); +} + +#define VIA_RNG_AVAILABLE (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS) \ + || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test()) + +INLINE int read_via_rng(void *buf, int count) +{ int nbr, max_reads, lcnt = count; + unsigned char *p, *q; + aligned_auto(unsigned char, bp, 64, 16); + + if(!VIA_RNG_AVAILABLE) + return 0; + + do + { + max_reads = MAX_READ_ATTEMPTS; + do + nbr = via_rng_in(bp); + while + (nbr == 0 && --max_reads); + + lcnt -= nbr; + p = (unsigned char*)buf; q = bp; + while(nbr--) + *p++ = *q++; + } + while + (lcnt && max_reads); + + return count - lcnt; +} + +#endif diff --git a/libs/minizip/source/aes/aescrypt.c b/libs/minizip/source/aes/aescrypt.c index 6095f41a..99141cf8 100644 --- a/libs/minizip/source/aes/aescrypt.c +++ b/libs/minizip/source/aes/aescrypt.c @@ -1,294 +1,294 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) -#define so(y,x,c) word_out(y, c, s(x,c)) - -#if defined(ARRAYS) -#define locals(y,x) x[4],y[4] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 -#endif - -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) -#pragma optimize( "s", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define fwd_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) - -#if defined(FT4_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) -#elif defined(FT1_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) -#else -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) -#endif - -#if defined(FL4_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) -#elif defined(FL1_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) -#else -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) -#endif - -AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) -{ uint_32t locals(b0, b1); - const uint_32t *kp; -#if defined( dec_fmvars ) - dec_fmvars; /* declare variables for fwd_mcol() if needed */ -#endif - - if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) - return EXIT_FAILURE; - - kp = cx->ks; - state_in(b0, in, kp); - -#if (ENC_UNROLL == FULL) - - switch(cx->inf.b[0]) - { - case 14 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - case 12 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - case 10 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - round(fwd_rnd, b1, b0, kp + 3 * N_COLS); - round(fwd_rnd, b0, b1, kp + 4 * N_COLS); - round(fwd_rnd, b1, b0, kp + 5 * N_COLS); - round(fwd_rnd, b0, b1, kp + 6 * N_COLS); - round(fwd_rnd, b1, b0, kp + 7 * N_COLS); - round(fwd_rnd, b0, b1, kp + 8 * N_COLS); - round(fwd_rnd, b1, b0, kp + 9 * N_COLS); - round(fwd_lrnd, b0, b1, kp +10 * N_COLS); - } - -#else - -#if (ENC_UNROLL == PARTIAL) - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - kp += N_COLS; - round(fwd_rnd, b0, b1, kp); - } - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); -#else - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp += N_COLS; - round(fwd_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) -#pragma optimize( "t", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define inv_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) - -#if defined(IT4_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) -#elif defined(IT1_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) -#else -#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) -#endif - -#if defined(IL4_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) -#elif defined(IL1_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) -#else -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) -#endif - -/* This code can work with the decryption key schedule in the */ -/* order that is used for encrytpion (where the 1st decryption */ -/* round key is at the high end ot the schedule) or with a key */ -/* schedule that has been reversed to put the 1st decryption */ -/* round key at the low end of the schedule in memory (when */ -/* AES_REV_DKS is defined) */ - -#ifdef AES_REV_DKS -#define key_ofs 0 -#define rnd_key(n) (kp + n * N_COLS) -#else -#define key_ofs 1 -#define rnd_key(n) (kp - n * N_COLS) -#endif - -AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) -{ uint_32t locals(b0, b1); -#if defined( dec_imvars ) - dec_imvars; /* declare variables for inv_mcol() if needed */ -#endif - const uint_32t *kp; - - if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) - return EXIT_FAILURE; - - kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); - state_in(b0, in, kp); - -#if (DEC_UNROLL == FULL) - - kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); - switch(cx->inf.b[0]) - { - case 14 * 16: - round(inv_rnd, b1, b0, rnd_key(-13)); - round(inv_rnd, b0, b1, rnd_key(-12)); - case 12 * 16: - round(inv_rnd, b1, b0, rnd_key(-11)); - round(inv_rnd, b0, b1, rnd_key(-10)); - case 10 * 16: - round(inv_rnd, b1, b0, rnd_key(-9)); - round(inv_rnd, b0, b1, rnd_key(-8)); - round(inv_rnd, b1, b0, rnd_key(-7)); - round(inv_rnd, b0, b1, rnd_key(-6)); - round(inv_rnd, b1, b0, rnd_key(-5)); - round(inv_rnd, b0, b1, rnd_key(-4)); - round(inv_rnd, b1, b0, rnd_key(-3)); - round(inv_rnd, b0, b1, rnd_key(-2)); - round(inv_rnd, b1, b0, rnd_key(-1)); - round(inv_lrnd, b0, b1, rnd_key( 0)); - } - -#else - -#if (DEC_UNROLL == PARTIAL) - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - kp = rnd_key(1); - round(inv_rnd, b0, b1, kp); - } - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); -#else - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp = rnd_key(1); - round(inv_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if defined(__cplusplus) -} -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) +#define so(y,x,c) word_out(y, c, s(x,c)) + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +#endif + +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "s", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) +#elif defined(FT1_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) +#else +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) +#else +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) +#endif + +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) +{ uint_32t locals(b0, b1); + const uint_32t *kp; +#if defined( dec_fmvars ) + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif + + if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) + return EXIT_FAILURE; + + kp = cx->ks; + state_in(b0, in, kp); + +#if (ENC_UNROLL == FULL) + + switch(cx->inf.b[0]) + { + case 14 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 12 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 10 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp +10 * N_COLS); + } + +#else + +#if (ENC_UNROLL == PARTIAL) + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + kp += N_COLS; + round(fwd_rnd, b0, b1, kp); + } + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); +#else + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp += N_COLS; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "t", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) + +#if defined(IT4_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) +#elif defined(IT1_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) +#else +#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) +#else +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) +#endif + +/* This code can work with the decryption key schedule in the */ +/* order that is used for encrytpion (where the 1st decryption */ +/* round key is at the high end ot the schedule) or with a key */ +/* schedule that has been reversed to put the 1st decryption */ +/* round key at the low end of the schedule in memory (when */ +/* AES_REV_DKS is defined) */ + +#ifdef AES_REV_DKS +#define key_ofs 0 +#define rnd_key(n) (kp + n * N_COLS) +#else +#define key_ofs 1 +#define rnd_key(n) (kp - n * N_COLS) +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) +{ uint_32t locals(b0, b1); +#if defined( dec_imvars ) + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + const uint_32t *kp; + + if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) + return EXIT_FAILURE; + + kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); + state_in(b0, in, kp); + +#if (DEC_UNROLL == FULL) + + kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); + switch(cx->inf.b[0]) + { + case 14 * 16: + round(inv_rnd, b1, b0, rnd_key(-13)); + round(inv_rnd, b0, b1, rnd_key(-12)); + case 12 * 16: + round(inv_rnd, b1, b0, rnd_key(-11)); + round(inv_rnd, b0, b1, rnd_key(-10)); + case 10 * 16: + round(inv_rnd, b1, b0, rnd_key(-9)); + round(inv_rnd, b0, b1, rnd_key(-8)); + round(inv_rnd, b1, b0, rnd_key(-7)); + round(inv_rnd, b0, b1, rnd_key(-6)); + round(inv_rnd, b1, b0, rnd_key(-5)); + round(inv_rnd, b0, b1, rnd_key(-4)); + round(inv_rnd, b1, b0, rnd_key(-3)); + round(inv_rnd, b0, b1, rnd_key(-2)); + round(inv_rnd, b1, b0, rnd_key(-1)); + round(inv_lrnd, b0, b1, rnd_key( 0)); + } + +#else + +#if (DEC_UNROLL == PARTIAL) + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + kp = rnd_key(1); + round(inv_rnd, b0, b1, kp); + } + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); +#else + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp = rnd_key(1); + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/aeskey.c b/libs/minizip/source/aes/aeskey.c index 3633641a..0378f0cf 100644 --- a/libs/minizip/source/aes/aeskey.c +++ b/libs/minizip/source/aes/aeskey.c @@ -1,548 +1,548 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -#ifdef USE_VIA_ACE_IF_PRESENT -# include "aes_via_ace.h" -#endif - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* Initialise the key schedule from the user supplied key. The key - length can be specified in bytes, with legal values of 16, 24 - and 32, or in bits, with legal values of 128, 192 and 256. These - values correspond with Nk values of 4, 6 and 8 respectively. - - The following macros implement a single cycle in the key - schedule generation process. The number of cycles needed - for each cx->n_col and nk value is: - - nk = 4 5 6 7 8 - ------------------------------ - cx->n_col = 4 10 9 8 7 7 - cx->n_col = 5 14 11 10 9 9 - cx->n_col = 6 19 15 12 11 11 - cx->n_col = 7 21 19 16 13 14 - cx->n_col = 8 29 23 19 17 14 -*/ - -#if defined( REDUCE_CODE_SIZE ) -# define ls_box ls_sub - uint_32t ls_sub(const uint_32t t, const uint_32t n); -# define inv_mcol im_sub - uint_32t im_sub(const uint_32t x); -# ifdef ENC_KS_UNROLL -# undef ENC_KS_UNROLL -# endif -# ifdef DEC_KS_UNROLL -# undef DEC_KS_UNROLL -# endif -#endif - -#if (FUNCS_IN_C & ENC_KEYING_IN_C) - -#if defined(AES_128) || defined( AES_VAR ) - -#define ke4(k,i) \ -{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; \ - k[4*(i)+7] = ss[3] ^= ss[2]; \ -} - -AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[4]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - -#ifdef ENC_KS_UNROLL - ke4(cx->ks, 0); ke4(cx->ks, 1); - ke4(cx->ks, 2); ke4(cx->ks, 3); - ke4(cx->ks, 4); ke4(cx->ks, 5); - ke4(cx->ks, 6); ke4(cx->ks, 7); - ke4(cx->ks, 8); -#else - { uint_32t i; - for(i = 0; i < 9; ++i) - ke4(cx->ks, i); - } -#endif - ke4(cx->ks, 9); - cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define kef6(k,i) \ -{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; \ - k[6*(i)+ 9] = ss[3] ^= ss[2]; \ -} - -#define ke6(k,i) \ -{ kef6(k,i); \ - k[6*(i)+10] = ss[4] ^= ss[3]; \ - k[6*(i)+11] = ss[5] ^= ss[4]; \ -} - -AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[6]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - -#ifdef ENC_KS_UNROLL - ke6(cx->ks, 0); ke6(cx->ks, 1); - ke6(cx->ks, 2); ke6(cx->ks, 3); - ke6(cx->ks, 4); ke6(cx->ks, 5); - ke6(cx->ks, 6); -#else - { uint_32t i; - for(i = 0; i < 7; ++i) - ke6(cx->ks, i); - } -#endif - kef6(cx->ks, 7); - cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define kef8(k,i) \ -{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; \ - k[8*(i)+11] = ss[3] ^= ss[2]; \ -} - -#define ke8(k,i) \ -{ kef8(k,i); \ - k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ - k[8*(i)+13] = ss[5] ^= ss[4]; \ - k[8*(i)+14] = ss[6] ^= ss[5]; \ - k[8*(i)+15] = ss[7] ^= ss[6]; \ -} - -AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[8]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - cx->ks[6] = ss[6] = word_in(key, 6); - cx->ks[7] = ss[7] = word_in(key, 7); - -#ifdef ENC_KS_UNROLL - ke8(cx->ks, 0); ke8(cx->ks, 1); - ke8(cx->ks, 2); ke8(cx->ks, 3); - ke8(cx->ks, 4); ke8(cx->ks, 5); -#else - { uint_32t i; - for(i = 0; i < 6; ++i) - ke8(cx->ks, i); - } -#endif - kef8(cx->ks, 6); - cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_VAR ) - -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_encrypt_key128(key, cx); - case 24: case 192: return aes_encrypt_key192(key, cx); - case 32: case 256: return aes_encrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -#endif - -#endif - -#if (FUNCS_IN_C & DEC_KEYING_IN_C) - -/* this is used to store the decryption round keys */ -/* in forward or reverse order */ - -#ifdef AES_REV_DKS -#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) -#else -#define v(n,i) (i) -#endif - -#if DEC_ROUND == NO_TABLES -#define ff(x) (x) -#else -#define ff(x) inv_mcol(x) -#if defined( dec_imvars ) -#define d_vars dec_imvars -#endif -#endif - -#if defined(AES_128) || defined( AES_VAR ) - -#define k4e(k,i) \ -{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ - k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ - k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ -} - -#if 1 - -#define kdf4(k,i) \ -{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ - ss[1] = ss[1] ^ ss[3]; \ - ss[2] = ss[2] ^ ss[3]; \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; \ - ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ - k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ - k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ - k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ -} - -#define kdl4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ - k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ - k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ - k[v(40,(4*(i))+6)] = ss[0]; \ - k[v(40,(4*(i))+7)] = ss[1]; \ -} - -#else - -#define kdf4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ -} - -#define kdl4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ -} - -#endif - -AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[5]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - kdf4(cx->ks, 0); kd4(cx->ks, 1); - kd4(cx->ks, 2); kd4(cx->ks, 3); - kd4(cx->ks, 4); kd4(cx->ks, 5); - kd4(cx->ks, 6); kd4(cx->ks, 7); - kd4(cx->ks, 8); kdl4(cx->ks, 9); -#else - { uint_32t i; - for(i = 0; i < 10; ++i) - k4e(cx->ks, i); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 10 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define k6ef(k,i) \ -{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ - k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ - k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ -} - -#define k6e(k,i) \ -{ k6ef(k,i); \ - k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ - k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ -} - -#define kdf6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ -} - -#define kd6(k,i) \ -{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ -} - -#define kdl6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ -} - -AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[7]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); - cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); - kdf6(cx->ks, 0); kd6(cx->ks, 1); - kd6(cx->ks, 2); kd6(cx->ks, 3); - kd6(cx->ks, 4); kd6(cx->ks, 5); - kd6(cx->ks, 6); kdl6(cx->ks, 7); -#else - cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); - { uint_32t i; - - for(i = 0; i < 7; ++i) - k6e(cx->ks, i); - k6ef(cx->ks, 7); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 12 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define k8ef(k,i) \ -{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ - k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ - k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ -} - -#define k8e(k,i) \ -{ k8ef(k,i); \ - k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ - k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ - k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ - k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ -} - -#define kdf8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ - ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ -} - -#define kd8(k,i) \ -{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ - ss[8] = ls_box(ss[3],0); \ - ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ -} - -#define kdl8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ -} - -AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[9]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); - cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); - cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); - cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); - kdf8(cx->ks, 0); kd8(cx->ks, 1); - kd8(cx->ks, 2); kd8(cx->ks, 3); - kd8(cx->ks, 4); kd8(cx->ks, 5); - kdl8(cx->ks, 6); -#else - cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); - cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); - cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); - { uint_32t i; - - for(i = 0; i < 6; ++i) - k8e(cx->ks, i); - k8ef(cx->ks, 6); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 14 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_VAR ) - -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_decrypt_key128(key, cx); - case 24: case 192: return aes_decrypt_key192(key, cx); - case 32: case 256: return aes_decrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -#endif - -#endif - -#if defined(__cplusplus) -} -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#ifdef USE_VIA_ACE_IF_PRESENT +# include "aes_via_ace.h" +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Initialise the key schedule from the user supplied key. The key + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#if defined( REDUCE_CODE_SIZE ) +# define ls_box ls_sub + uint_32t ls_sub(const uint_32t t, const uint_32t n); +# define inv_mcol im_sub + uint_32t im_sub(const uint_32t x); +# ifdef ENC_KS_UNROLL +# undef ENC_KS_UNROLL +# endif +# ifdef DEC_KS_UNROLL +# undef DEC_KS_UNROLL +# endif +#endif + +#if (FUNCS_IN_C & ENC_KEYING_IN_C) + +#if defined(AES_128) || defined( AES_VAR ) + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; \ + k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[4]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + +#ifdef ENC_KS_UNROLL + ke4(cx->ks, 0); ke4(cx->ks, 1); + ke4(cx->ks, 2); ke4(cx->ks, 3); + ke4(cx->ks, 4); ke4(cx->ks, 5); + ke4(cx->ks, 6); ke4(cx->ks, 7); + ke4(cx->ks, 8); +#else + { uint_32t i; + for(i = 0; i < 9; ++i) + ke4(cx->ks, i); + } +#endif + ke4(cx->ks, 9); + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define kef6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; \ + k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ kef6(k,i); \ + k[6*(i)+10] = ss[4] ^= ss[3]; \ + k[6*(i)+11] = ss[5] ^= ss[4]; \ +} + +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[6]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + +#ifdef ENC_KS_UNROLL + ke6(cx->ks, 0); ke6(cx->ks, 1); + ke6(cx->ks, 2); ke6(cx->ks, 3); + ke6(cx->ks, 4); ke6(cx->ks, 5); + ke6(cx->ks, 6); +#else + { uint_32t i; + for(i = 0; i < 7; ++i) + ke6(cx->ks, i); + } +#endif + kef6(cx->ks, 7); + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define kef8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; \ + k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ kef8(k,i); \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ + k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; \ + k[8*(i)+15] = ss[7] ^= ss[6]; \ +} + +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[8]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + cx->ks[6] = ss[6] = word_in(key, 6); + cx->ks[7] = ss[7] = word_in(key, 7); + +#ifdef ENC_KS_UNROLL + ke8(cx->ks, 0); ke8(cx->ks, 1); + ke8(cx->ks, 2); ke8(cx->ks, 3); + ke8(cx->ks, 4); ke8(cx->ks, 5); +#else + { uint_32t i; + for(i = 0; i < 6; ++i) + ke8(cx->ks, i); + } +#endif + kef8(cx->ks, 6); + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_encrypt_key128(key, cx); + case 24: case 192: return aes_encrypt_key192(key, cx); + case 32: case 256: return aes_encrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#endif + +#if (FUNCS_IN_C & DEC_KEYING_IN_C) + +/* this is used to store the decryption round keys */ +/* in forward or reverse order */ + +#ifdef AES_REV_DKS +#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) +#else +#define v(n,i) (i) +#endif + +#if DEC_ROUND == NO_TABLES +#define ff(x) (x) +#else +#define ff(x) inv_mcol(x) +#if defined( dec_imvars ) +#define d_vars dec_imvars +#endif +#endif + +#if defined(AES_128) || defined( AES_VAR ) + +#define k4e(k,i) \ +{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ + k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ + k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ +} + +#if 1 + +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ + ss[1] = ss[1] ^ ss[3]; \ + ss[2] = ss[2] ^ ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ + k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ + k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ +} + +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ + k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ + k[v(40,(4*(i))+6)] = ss[0]; \ + k[v(40,(4*(i))+7)] = ss[1]; \ +} + +#else + +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ +} + +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ +} + +#endif + +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[5]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + kdf4(cx->ks, 0); kd4(cx->ks, 1); + kd4(cx->ks, 2); kd4(cx->ks, 3); + kd4(cx->ks, 4); kd4(cx->ks, 5); + kd4(cx->ks, 6); kd4(cx->ks, 7); + kd4(cx->ks, 8); kdl4(cx->ks, 9); +#else + { uint_32t i; + for(i = 0; i < 10; ++i) + k4e(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define k6ef(k,i) \ +{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ + k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ + k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ +} + +#define k6e(k,i) \ +{ k6ef(k,i); \ + k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ + k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ +} + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ +} + +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ +} + +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ +} + +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[7]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); + kdf6(cx->ks, 0); kd6(cx->ks, 1); + kd6(cx->ks, 2); kd6(cx->ks, 3); + kd6(cx->ks, 4); kd6(cx->ks, 5); + kd6(cx->ks, 6); kdl6(cx->ks, 7); +#else + cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); + { uint_32t i; + + for(i = 0; i < 7; ++i) + k6e(cx->ks, i); + k6ef(cx->ks, 7); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define k8ef(k,i) \ +{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ + k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ + k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ +} + +#define k8e(k,i) \ +{ k8ef(k,i); \ + k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ + k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ + k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ + k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ +} + +#define kd8(k,i) \ +{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ + ss[8] = ls_box(ss[3],0); \ + ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ +} + +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ +} + +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[9]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); + cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); + cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); + kdf8(cx->ks, 0); kd8(cx->ks, 1); + kd8(cx->ks, 2); kd8(cx->ks, 3); + kd8(cx->ks, 4); kd8(cx->ks, 5); + kdl8(cx->ks, 6); +#else + cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); + cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); + cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); + { uint_32t i; + + for(i = 0; i < 6; ++i) + k8e(cx->ks, i); + k8ef(cx->ks, 6); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_decrypt_key128(key, cx); + case 24: case 192: return aes_decrypt_key192(key, cx); + case 32: case 256: return aes_decrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/aesopt.h b/libs/minizip/source/aes/aesopt.h index fd8db2ec..8851425e 100644 --- a/libs/minizip/source/aes/aesopt.h +++ b/libs/minizip/source/aes/aesopt.h @@ -1,739 +1,739 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the compilation options for AES (Rijndael) and code - that is common across encryption, key scheduling and table generation. - - OPERATION - - These source code files implement the AES algorithm Rijndael designed by - Joan Daemen and Vincent Rijmen. This version is designed for the standard - block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 - and 32 bytes). - - This version is designed for flexibility and speed using operations on - 32-bit words rather than operations on bytes. It can be compiled with - either big or little endian internal byte order but is faster when the - native byte order for the processor is used. - - THE CIPHER INTERFACE - - The cipher interface is implemented as an array of bytes in which lower - AES bit sequence indexes map to higher numeric significance within bytes. - - uint_8t (an unsigned 8-bit type) - uint_32t (an unsigned 32-bit type) - struct aes_encrypt_ctx (structure for the cipher encryption context) - struct aes_decrypt_ctx (structure for the cipher decryption context) - AES_RETURN the function return type - - C subroutine calls: - - AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, - const aes_encrypt_ctx cx[1]); - - AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, - const aes_decrypt_ctx cx[1]); - - IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that - you call aes_init() before AES is used so that the tables are initialised. - - C++ aes class subroutines: - - Class AESencrypt for encryption - - Construtors: - AESencrypt(void) - AESencrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const - - Class AESdecrypt for encryption - Construtors: - AESdecrypt(void) - AESdecrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const -*/ - -#if !defined( _AESOPT_H ) -#define _AESOPT_H - -#if defined( __cplusplus ) -#include "aescpp.h" -#else -#include "aes.h" -#endif - -/* PLATFORM SPECIFIC INCLUDES */ - -#include "brg_endian.h" - -/* CONFIGURATION - THE USE OF DEFINES - - Later in this section there are a number of defines that control the - operation of the code. In each section, the purpose of each define is - explained so that the relevant form can be included or excluded by - setting either 1's or 0's respectively on the branches of the related - #if clauses. The following local defines should not be changed. -*/ - -#define ENCRYPTION_IN_C 1 -#define DECRYPTION_IN_C 2 -#define ENC_KEYING_IN_C 4 -#define DEC_KEYING_IN_C 8 - -#define NO_TABLES 0 -#define ONE_TABLE 1 -#define FOUR_TABLES 4 -#define NONE 0 -#define PARTIAL 1 -#define FULL 2 - -/* --- START OF USER CONFIGURED OPTIONS --- */ - -/* 1. BYTE ORDER WITHIN 32 BIT WORDS - - The fundamental data processing units in Rijndael are 8-bit bytes. The - input, output and key input are all enumerated arrays of bytes in which - bytes are numbered starting at zero and increasing to one less than the - number of bytes in the array in question. This enumeration is only used - for naming bytes and does not imply any adjacency or order relationship - from one byte to another. When these inputs and outputs are considered - as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to - byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. - In this implementation bits are numbered from 0 to 7 starting at the - numerically least significant end of each byte (bit n represents 2^n). - - However, Rijndael can be implemented more efficiently using 32-bit - words by packing bytes into words so that bytes 4*n to 4*n+3 are placed - into word[n]. While in principle these bytes can be assembled into words - in any positions, this implementation only supports the two formats in - which bytes in adjacent positions within words also have adjacent byte - numbers. This order is called big-endian if the lowest numbered bytes - in words have the highest numeric significance and little-endian if the - opposite applies. - - This code can work in either order irrespective of the order used by the - machine on which it runs. Normally the internal byte order will be set - to the order of the processor on which the code is to be run but this - define can be used to reverse this in special situations - - WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. - This define will hence be redefined later (in section 4) if necessary -*/ - -#if 1 -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error The algorithm byte order is not defined -#endif - -/* 2. VIA ACE SUPPORT */ - -#if !defined(__APPLE__) && defined( __GNUC__ ) && defined( __i386__ ) \ - || defined( _WIN32 ) && defined( _M_IX86 ) \ - && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define VIA_ACE_POSSIBLE -#endif - -/* Define this option if support for the VIA ACE is required. This uses - inline assembler instructions and is only implemented for the Microsoft, - Intel and GCC compilers. If VIA ACE is known to be present, then defining - ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption - code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if - it is detected (both present and enabled) but the normal AES code will - also be present. - - When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte - aligned; other input/output buffers do not need to be 16 byte aligned - but there are very large performance gains if this can be arranged. - VIA ACE also requires the decryption key schedule to be in reverse - order (which later checks below ensure). -*/ - -#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) -# define ASSUME_VIA_ACE_PRESENT -# endif - -/* 3. ASSEMBLER SUPPORT - - This define (which can be on the command line) enables the use of the - assembler code routines for encryption, decryption and key scheduling - as follows: - - ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for - encryption and decryption and but with key scheduling in C - ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for - encryption, decryption and key scheduling - ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - - Change one 'if 0' below to 'if 1' to select the version or define - as a compilation option. -*/ - -#if 0 && !defined( ASM_X86_V1C ) -# define ASM_X86_V1C -#elif 0 && !defined( ASM_X86_V2 ) -# define ASM_X86_V2 -#elif 0 && !defined( ASM_X86_V2C ) -# define ASM_X86_V2C -#elif 0 && !defined( ASM_AMD64_C ) -# define ASM_AMD64_C -#endif - -#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ - && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) -# error Assembler code is only available for x86 and AMD64 systems -#endif - -/* 4. FAST INPUT/OUTPUT OPERATIONS. - - On some machines it is possible to improve speed by transferring the - bytes in the input and output arrays to and from the internal 32-bit - variables by addressing these arrays as if they are arrays of 32-bit - words. On some machines this will always be possible but there may - be a large performance penalty if the byte arrays are not aligned on - the normal word boundaries. On other machines this technique will - lead to memory access errors when such 32-bit word accesses are not - properly aligned. The option SAFE_IO avoids such problems but will - often be slower on those machines that support misaligned access - (especially so if care is taken to align the input and output byte - arrays on 32-bit word boundaries). If SAFE_IO is not defined it is - assumed that access to byte arrays as if they are arrays of 32-bit - words will not cause problems when such accesses are misaligned. -*/ -#if 1 && !defined( _MSC_VER ) -# define SAFE_IO -#endif - -/* 5. LOOP UNROLLING - - The code for encryption and decrytpion cycles through a number of rounds - that can be implemented either in a loop or by expanding the code into a - long sequence of instructions, the latter producing a larger program but - one that will often be much faster. The latter is called loop unrolling. - There are also potential speed advantages in expanding two iterations in - a loop with half the number of iterations, which is called partial loop - unrolling. The following options allow partial or full loop unrolling - to be set independently for encryption and decryption -*/ -#if 1 -# define ENC_UNROLL FULL -#elif 0 -# define ENC_UNROLL PARTIAL -#else -# define ENC_UNROLL NONE -#endif - -#if 1 -# define DEC_UNROLL FULL -#elif 0 -# define DEC_UNROLL PARTIAL -#else -# define DEC_UNROLL NONE -#endif - -#if 1 -# define ENC_KS_UNROLL -#endif - -#if 1 -# define DEC_KS_UNROLL -#endif - -/* 6. FAST FINITE FIELD OPERATIONS - - If this section is included, tables are used to provide faster finite - field arithmetic (this has no effect if FIXED_TABLES is defined). -*/ -#if 1 -# define FF_TABLES -#endif - -/* 7. INTERNAL STATE VARIABLE FORMAT - - The internal state of Rijndael is stored in a number of local 32-bit - word varaibles which can be defined either as an array or as individual - names variables. Include this section if you want to store these local - varaibles in arrays. Otherwise individual local variables will be used. -*/ -#if 1 -# define ARRAYS -#endif - -/* 8. FIXED OR DYNAMIC TABLES - - When this section is included the tables used by the code are compiled - statically into the binary file. Otherwise the subroutine aes_init() - must be called to compute them before the code is first used. -*/ -#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define FIXED_TABLES -#endif - -/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES - - In some systems it is better to mask longer values to extract bytes - rather than using a cast. This option allows this choice. -*/ -#if 0 -# define to_byte(x) ((uint_8t)(x)) -#else -# define to_byte(x) ((x) & 0xff) -#endif - -/* 10. TABLE ALIGNMENT - - On some sytsems speed will be improved by aligning the AES large lookup - tables on particular boundaries. This define should be set to a power of - two giving the desired alignment. It can be left undefined if alignment - is not needed. This option is specific to the Microsft VC++ compiler - - it seems to sometimes cause trouble for the VC++ version 6 compiler. -*/ - -#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# define TABLE_ALIGN 32 -#endif - -/* 11. REDUCE CODE AND TABLE SIZE - - This replaces some expanded macros with function calls if AES_ASM_V2 or - AES_ASM_V2C are defined -*/ - -#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) -# define REDUCE_CODE_SIZE -#endif - -/* 12. TABLE OPTIONS - - This cipher proceeds by repeating in a number of cycles known as 'rounds' - which are implemented by a round function which can optionally be speeded - up using tables. The basic tables are each 256 32-bit words, with either - one or four tables being required for each round function depending on - how much speed is required. The encryption and decryption round functions - are different and the last encryption and decrytpion round functions are - different again making four different round functions in all. - - This means that: - 1. Normal encryption and decryption rounds can each use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - 2. The last encryption and decryption rounds can also use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - - Include or exclude the appropriate definitions below to set the number - of tables used by this implementation. -*/ - -#if 1 /* set tables for the normal encryption round */ -# define ENC_ROUND FOUR_TABLES -#elif 0 -# define ENC_ROUND ONE_TABLE -#else -# define ENC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the last encryption round */ -# define LAST_ENC_ROUND FOUR_TABLES -#elif 0 -# define LAST_ENC_ROUND ONE_TABLE -#else -# define LAST_ENC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the normal decryption round */ -# define DEC_ROUND FOUR_TABLES -#elif 0 -# define DEC_ROUND ONE_TABLE -#else -# define DEC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the last decryption round */ -# define LAST_DEC_ROUND FOUR_TABLES -#elif 0 -# define LAST_DEC_ROUND ONE_TABLE -#else -# define LAST_DEC_ROUND NO_TABLES -#endif - -/* The decryption key schedule can be speeded up with tables in the same - way that the round functions can. Include or exclude the following - defines to set this requirement. -*/ -#if 1 -# define KEY_SCHED FOUR_TABLES -#elif 0 -# define KEY_SCHED ONE_TABLE -#else -# define KEY_SCHED NO_TABLES -#endif - -/* ---- END OF USER CONFIGURED OPTIONS ---- */ - -/* VIA ACE support is only available for VC++ and GCC */ - -#if !defined( _MSC_VER ) && !defined( __GNUC__ ) -# if defined( ASSUME_VIA_ACE_PRESENT ) -# undef ASSUME_VIA_ACE_PRESENT -# endif -# if defined( USE_VIA_ACE_IF_PRESENT ) -# undef USE_VIA_ACE_IF_PRESENT -# endif -#endif - -#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) -# define AES_REV_DKS -#endif - -/* Assembler support requires the use of platform byte order */ - -#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ - && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) -# undef ALGORITHM_BYTE_ORDER -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#endif - -/* In this implementation the columns of the state array are each held in - 32-bit words. The state array can be held in various ways: in an array - of words, in a number of individual word variables or in a number of - processor registers. The following define maps a variable name x and - a column number c to the way the state array variable is to be held. - The first define below maps the state into an array x[c] whereas the - second form maps the state into a number of individual variables x0, - x1, etc. Another form could map individual state colums to machine - register names. -*/ - -#if defined( ARRAYS ) -# define s(x,c) x[c] -#else -# define s(x,c) x##c -#endif - -/* This implementation provides subroutines for encryption, decryption - and for setting the three key lengths (separately) for encryption - and decryption. Since not all functions are needed, masks are set - up here to determine which will be implemented in C -*/ - -#if !defined( AES_ENCRYPT ) -# define EFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define EFUNCS_IN_C ENC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) -#else -# define EFUNCS_IN_C 0 -#endif - -#if !defined( AES_DECRYPT ) -# define DFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define DFUNCS_IN_C DEC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) -#else -# define DFUNCS_IN_C 0 -#endif - -#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) - -/* END OF CONFIGURATION OPTIONS */ - -#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) - -/* Disable or report errors on some combinations of options */ - -#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND NO_TABLES -#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND ONE_TABLE -#endif - -#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE -# undef ENC_UNROLL -# define ENC_UNROLL NONE -#endif - -#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND NO_TABLES -#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND ONE_TABLE -#endif - -#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE -# undef DEC_UNROLL -# define DEC_UNROLL NONE -#endif - -#if defined( bswap32 ) -# define aes_sw32 bswap32 -#elif defined( bswap_32 ) -# define aes_sw32 bswap_32 -#else -# define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n))) -# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) -#endif - -/* upr(x,n): rotates bytes within words by n positions, moving bytes to - higher index positions with wrap around into low positions - ups(x,n): moves bytes by n positions to higher index positions in - words but without wrap around - bval(x,n): extracts a byte from a word - - WARNING: The definitions given here are intended only for use with - unsigned variables and with shift counts that are compile - time constants -*/ - -#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) -# define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n)))) -# define ups(x,n) ((uint_32t) (x) << (8 * (n))) -# define bval(x,n) to_byte((x) >> (8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0)) -#endif - -#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) -# define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n)))) -# define ups(x,n) ((uint_32t) (x) >> (8 * (n))) -# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3)) -#endif - -#if defined( SAFE_IO ) -# define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \ - ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3]) -# define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \ - ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); } -#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) -# define word_in(x,c) (*((uint_32t*)(x)+(c))) -# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v)) -#else -# define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c))) -# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v)) -#endif - -/* the finite field modular polynomial and elements */ - -#define WPOLY 0x011b -#define BPOLY 0x1b - -/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ - -#define gf_c1 0x80808080 -#define gf_c2 0x7f7f7f7f -#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) - -/* The following defines provide alternative definitions of gf_mulx that might - give improved performance if a fast 32-bit multiply is not available. Note - that a temporary variable u needs to be defined where gf_mulx is used. - -#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) -#define gf_c4 (0x01010101 * BPOLY) -#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) -*/ - -/* Work out which tables are needed for the different options */ - -#if defined( ASM_X86_V1C ) -# if defined( ENC_ROUND ) -# undef ENC_ROUND -# endif -# define ENC_ROUND FOUR_TABLES -# if defined( LAST_ENC_ROUND ) -# undef LAST_ENC_ROUND -# endif -# define LAST_ENC_ROUND FOUR_TABLES -# if defined( DEC_ROUND ) -# undef DEC_ROUND -# endif -# define DEC_ROUND FOUR_TABLES -# if defined( LAST_DEC_ROUND ) -# undef LAST_DEC_ROUND -# endif -# define LAST_DEC_ROUND FOUR_TABLES -# if defined( KEY_SCHED ) -# undef KEY_SCHED -# define KEY_SCHED FOUR_TABLES -# endif -#endif - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if ENC_ROUND == ONE_TABLE -# define FT1_SET -# elif ENC_ROUND == FOUR_TABLES -# define FT4_SET -# else -# define SBX_SET -# endif -# if LAST_ENC_ROUND == ONE_TABLE -# define FL1_SET -# elif LAST_ENC_ROUND == FOUR_TABLES -# define FL4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if DEC_ROUND == ONE_TABLE -# define IT1_SET -# elif DEC_ROUND == FOUR_TABLES -# define IT4_SET -# else -# define ISB_SET -# endif -# if LAST_DEC_ROUND == ONE_TABLE -# define IL1_SET -# elif LAST_DEC_ROUND == FOUR_TABLES -# define IL4_SET -# elif !defined(ISB_SET) -# define ISB_SET -# endif -#endif - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) -# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) -# if KEY_SCHED == ONE_TABLE -# if !defined( FL1_SET ) && !defined( FL4_SET ) -# define LS1_SET -# endif -# elif KEY_SCHED == FOUR_TABLES -# if !defined( FL4_SET ) -# define LS4_SET -# endif -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -# if (FUNCS_IN_C & DEC_KEYING_IN_C) -# if KEY_SCHED == ONE_TABLE -# define IM1_SET -# elif KEY_SCHED == FOUR_TABLES -# define IM4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -#endif - -/* generic definitions of Rijndael macros that use tables */ - -#define no_table(x,box,vf,rf,c) bytes2word( \ - box[bval(vf(x,0,c),rf(0,c))], \ - box[bval(vf(x,1,c),rf(1,c))], \ - box[bval(vf(x,2,c),rf(2,c))], \ - box[bval(vf(x,3,c),rf(3,c))]) - -#define one_table(x,op,tab,vf,rf,c) \ - ( tab[bval(vf(x,0,c),rf(0,c))] \ - ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ - ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ - ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) - -#define four_tables(x,tab,vf,rf,c) \ - ( tab[0][bval(vf(x,0,c),rf(0,c))] \ - ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ - ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ - ^ tab[3][bval(vf(x,3,c),rf(3,c))]) - -#define vf1(x,r,c) (x) -#define rf1(r,c) (r) -#define rf2(r,c) ((8+r-c)&3) - -/* perform forward and inverse column mix operation on four bytes in long word x in */ -/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) - -#if defined( FM4_SET ) /* not currently used */ -# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) -#elif defined( FM1_SET ) /* not currently used */ -# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) -#else -# define dec_fmvars uint_32t g2 -# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) -#endif - -#if defined( IM4_SET ) -# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) -#elif defined( IM1_SET ) -# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) -#else -# define dec_imvars uint_32t g2, g4, g9 -# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ - (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) -#endif - -#if defined( FL4_SET ) -# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) -#elif defined( LS4_SET ) -# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) -#elif defined( FL1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) -#elif defined( LS1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) -#else -# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) -#endif - -#endif - -#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) -# define ISB_SET -#endif - -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + uint_8t (an unsigned 8-bit type) + uint_32t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + AES_RETURN the function return type + + C subroutine calls: + + AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, + const aes_encrypt_ctx cx[1]); + + AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, + const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call aes_init() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Construtors: + AESencrypt(void) + AESencrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const + + Class AESdecrypt for encryption + Construtors: + AESdecrypt(void) + AESdecrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const +*/ + +#if !defined( _AESOPT_H ) +#define _AESOPT_H + +#if defined( __cplusplus ) +#include "aescpp.h" +#else +#include "aes.h" +#endif + +/* PLATFORM SPECIFIC INCLUDES */ + +#include "brg_endian.h" + +/* CONFIGURATION - THE USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. The following local defines should not be changed. +*/ + +#define ENCRYPTION_IN_C 1 +#define DECRYPTION_IN_C 2 +#define ENC_KEYING_IN_C 4 +#define DEC_KEYING_IN_C 8 + +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 + +/* --- START OF USER CONFIGURED OPTIONS --- */ + +/* 1. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations + + WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. + This define will hence be redefined later (in section 4) if necessary +*/ + +#if 1 +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error The algorithm byte order is not defined +#endif + +/* 2. VIA ACE SUPPORT */ + +#if !defined(__APPLE__) && defined( __GNUC__ ) && defined( __i386__ ) \ + || defined( _WIN32 ) && defined( _M_IX86 ) \ + && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define VIA_ACE_POSSIBLE +#endif + +/* Define this option if support for the VIA ACE is required. This uses + inline assembler instructions and is only implemented for the Microsoft, + Intel and GCC compilers. If VIA ACE is known to be present, then defining + ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption + code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if + it is detected (both present and enabled) but the normal AES code will + also be present. + + When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte + aligned; other input/output buffers do not need to be 16 byte aligned + but there are very large performance gains if this can be arranged. + VIA ACE also requires the decryption key schedule to be in reverse + order (which later checks below ensure). +*/ + +#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) +# define ASSUME_VIA_ACE_PRESENT +# endif + +/* 3. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption, decryption and key scheduling + as follows: + + ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for + encryption and decryption and but with key scheduling in C + ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for + encryption, decryption and key scheduling + ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + + Change one 'if 0' below to 'if 1' to select the version or define + as a compilation option. +*/ + +#if 0 && !defined( ASM_X86_V1C ) +# define ASM_X86_V1C +#elif 0 && !defined( ASM_X86_V2 ) +# define ASM_X86_V2 +#elif 0 && !defined( ASM_X86_V2C ) +# define ASM_X86_V2C +#elif 0 && !defined( ASM_AMD64_C ) +# define ASM_AMD64_C +#endif + +#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ + && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) +# error Assembler code is only available for x86 and AMD64 systems +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 && !defined( _MSC_VER ) +# define SAFE_IO +#endif + +/* 5. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +# define ENC_UNROLL FULL +#elif 0 +# define ENC_UNROLL PARTIAL +#else +# define ENC_UNROLL NONE +#endif + +#if 1 +# define DEC_UNROLL FULL +#elif 0 +# define DEC_UNROLL PARTIAL +#else +# define DEC_UNROLL NONE +#endif + +#if 1 +# define ENC_KS_UNROLL +#endif + +#if 1 +# define DEC_KS_UNROLL +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if FIXED_TABLES is defined). +*/ +#if 1 +# define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +# define ARRAYS +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine aes_init() + must be called to compute them before the code is first used. +*/ +#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define FIXED_TABLES +#endif + +/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES + + In some systems it is better to mask longer values to extract bytes + rather than using a cast. This option allows this choice. +*/ +#if 0 +# define to_byte(x) ((uint_8t)(x)) +#else +# define to_byte(x) ((x) & 0xff) +#endif + +/* 10. TABLE ALIGNMENT + + On some sytsems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. +*/ + +#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# define TABLE_ALIGN 32 +#endif + +/* 11. REDUCE CODE AND TABLE SIZE + + This replaces some expanded macros with function calls if AES_ASM_V2 or + AES_ASM_V2C are defined +*/ + +#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) +# define REDUCE_CODE_SIZE +#endif + +/* 12. TABLE OPTIONS + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +# define ENC_ROUND FOUR_TABLES +#elif 0 +# define ENC_ROUND ONE_TABLE +#else +# define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +# define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +# define LAST_ENC_ROUND ONE_TABLE +#else +# define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +# define DEC_ROUND FOUR_TABLES +#elif 0 +# define DEC_ROUND ONE_TABLE +#else +# define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +# define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +# define LAST_DEC_ROUND ONE_TABLE +#else +# define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +# define KEY_SCHED FOUR_TABLES +#elif 0 +# define KEY_SCHED ONE_TABLE +#else +# define KEY_SCHED NO_TABLES +#endif + +/* ---- END OF USER CONFIGURED OPTIONS ---- */ + +/* VIA ACE support is only available for VC++ and GCC */ + +#if !defined( _MSC_VER ) && !defined( __GNUC__ ) +# if defined( ASSUME_VIA_ACE_PRESENT ) +# undef ASSUME_VIA_ACE_PRESENT +# endif +# if defined( USE_VIA_ACE_IF_PRESENT ) +# undef USE_VIA_ACE_IF_PRESENT +# endif +#endif + +#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) +# define AES_REV_DKS +#endif + +/* Assembler support requires the use of platform byte order */ + +#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ + && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) +# undef ALGORITHM_BYTE_ORDER +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined( ARRAYS ) +# define s(x,c) x[c] +#else +# define s(x,c) x##c +#endif + +/* This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. Since not all functions are needed, masks are set + up here to determine which will be implemented in C +*/ + +#if !defined( AES_ENCRYPT ) +# define EFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define EFUNCS_IN_C ENC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) +#else +# define EFUNCS_IN_C 0 +#endif + +#if !defined( AES_DECRYPT ) +# define DFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define DFUNCS_IN_C DEC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) +#else +# define DFUNCS_IN_C 0 +#endif + +#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) + +/* END OF CONFIGURATION OPTIONS */ + +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) + +/* Disable or report errors on some combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +# undef ENC_UNROLL +# define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +# undef DEC_UNROLL +# define DEC_UNROLL NONE +#endif + +#if defined( bswap32 ) +# define aes_sw32 bswap32 +#elif defined( bswap_32 ) +# define aes_sw32 bswap_32 +#else +# define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n))) +# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + WARNING: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) +# define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n)))) +# define ups(x,n) ((uint_32t) (x) << (8 * (n))) +# define bval(x,n) to_byte((x) >> (8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0)) +#endif + +#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) +# define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n)))) +# define ups(x,n) ((uint_32t) (x) >> (8 * (n))) +# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3)) +#endif + +#if defined( SAFE_IO ) +# define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \ + ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3]) +# define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \ + ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); } +#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) +# define word_in(x,c) (*((uint_32t*)(x)+(c))) +# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v)) +#else +# define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c))) +# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v)) +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define gf_c1 0x80808080 +#define gf_c2 0x7f7f7f7f +#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. + +#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) +#define gf_c4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) +*/ + +/* Work out which tables are needed for the different options */ + +#if defined( ASM_X86_V1C ) +# if defined( ENC_ROUND ) +# undef ENC_ROUND +# endif +# define ENC_ROUND FOUR_TABLES +# if defined( LAST_ENC_ROUND ) +# undef LAST_ENC_ROUND +# endif +# define LAST_ENC_ROUND FOUR_TABLES +# if defined( DEC_ROUND ) +# undef DEC_ROUND +# endif +# define DEC_ROUND FOUR_TABLES +# if defined( LAST_DEC_ROUND ) +# undef LAST_DEC_ROUND +# endif +# define LAST_DEC_ROUND FOUR_TABLES +# if defined( KEY_SCHED ) +# undef KEY_SCHED +# define KEY_SCHED FOUR_TABLES +# endif +#endif + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if ENC_ROUND == ONE_TABLE +# define FT1_SET +# elif ENC_ROUND == FOUR_TABLES +# define FT4_SET +# else +# define SBX_SET +# endif +# if LAST_ENC_ROUND == ONE_TABLE +# define FL1_SET +# elif LAST_ENC_ROUND == FOUR_TABLES +# define FL4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if DEC_ROUND == ONE_TABLE +# define IT1_SET +# elif DEC_ROUND == FOUR_TABLES +# define IT4_SET +# else +# define ISB_SET +# endif +# if LAST_DEC_ROUND == ONE_TABLE +# define IL1_SET +# elif LAST_DEC_ROUND == FOUR_TABLES +# define IL4_SET +# elif !defined(ISB_SET) +# define ISB_SET +# endif +#endif + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) +# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) +# if KEY_SCHED == ONE_TABLE +# if !defined( FL1_SET ) && !defined( FL4_SET ) +# define LS1_SET +# endif +# elif KEY_SCHED == FOUR_TABLES +# if !defined( FL4_SET ) +# define LS4_SET +# endif +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +# if (FUNCS_IN_C & DEC_KEYING_IN_C) +# if KEY_SCHED == ONE_TABLE +# define IM1_SET +# elif KEY_SCHED == FOUR_TABLES +# define IM4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((8+r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) + +#if defined( FM4_SET ) /* not currently used */ +# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) +#elif defined( FM1_SET ) /* not currently used */ +# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) +#else +# define dec_fmvars uint_32t g2 +# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) +#endif + +#if defined( IM4_SET ) +# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) +#elif defined( IM1_SET ) +# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) +#else +# define dec_imvars uint_32t g2, g4, g9 +# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined( FL4_SET ) +# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) +#elif defined( LS4_SET ) +# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) +#elif defined( FL1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) +#elif defined( LS1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) +#else +# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) +#endif + +#endif + +#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) +# define ISB_SET +#endif + +#endif diff --git a/libs/minizip/source/aes/aestab.c b/libs/minizip/source/aes/aestab.c index e2bdb9a7..6d193aff 100644 --- a/libs/minizip/source/aes/aestab.c +++ b/libs/minizip/source/aes/aestab.c @@ -1,391 +1,391 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#define DO_TABLES - -#include "aes.h" -#include "aesopt.h" - -#if defined(FIXED_TABLES) - -#define sb_data(w) {\ - w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ - w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ - w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ - w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ - w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ - w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ - w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ - w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ - w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ - w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ - w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ - w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ - w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ - w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ - w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ - w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ - w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ - w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ - w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ - w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ - w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ - w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ - w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ - w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ - w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ - w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ - w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ - w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ - w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ - w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ - w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ - w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } - -#define isb_data(w) {\ - w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ - w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ - w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ - w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ - w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ - w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ - w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ - w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ - w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ - w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ - w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ - w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ - w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ - w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ - w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ - w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ - w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ - w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ - w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ - w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ - w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ - w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ - w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ - w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ - w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ - w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ - w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ - w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ - w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ - w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ - w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ - w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } - -#define mm_data(w) {\ - w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ - w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ - w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ - w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ - w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ - w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ - w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ - w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ - w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ - w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ - w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ - w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ - w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ - w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ - w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ - w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ - w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ - w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ - w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ - w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ - w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ - w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ - w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ - w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ - w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ - w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ - w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ - w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ - w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ - w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ - w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ - w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } - -#define rc_data(w) {\ - w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ - w(0x1b), w(0x36) } - -#define h0(x) (x) - -#define w0(p) bytes2word(p, 0, 0, 0) -#define w1(p) bytes2word(0, p, 0, 0) -#define w2(p) bytes2word(0, 0, p, 0) -#define w3(p) bytes2word(0, 0, 0, p) - -#define u0(p) bytes2word(f2(p), p, p, f3(p)) -#define u1(p) bytes2word(f3(p), f2(p), p, p) -#define u2(p) bytes2word(p, f3(p), f2(p), p) -#define u3(p) bytes2word(p, p, f3(p), f2(p)) - -#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) -#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) -#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) -#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) - -#endif - -#if defined(FIXED_TABLES) || !defined(FF_TABLES) - -#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) -#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) -#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ - ^ (((x>>5) & 4) * WPOLY)) -#define f3(x) (f2(x) ^ x) -#define f9(x) (f8(x) ^ x) -#define fb(x) (f8(x) ^ f2(x) ^ x) -#define fd(x) (f8(x) ^ f4(x) ^ x) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) - -#else - -#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) -#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) -#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) -#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) -#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) -#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) - -#endif - -#include "aestab.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined(FIXED_TABLES) - -/* implemented in case of wrong call for fixed tables */ - -AES_RETURN aes_init(void) -{ - return EXIT_SUCCESS; -} - -#else /* Generate the tables for the dynamic table option */ - -#if defined(FF_TABLES) - -#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) - -#else - -/* It will generally be sensible to use tables to compute finite - field multiplies and inverses but where memory is scarse this - code might sometimes be better. But it only has effect during - initialisation so its pretty unimportant in overall terms. -*/ - -/* return 2 ^ (n - 1) where n is the bit number of the highest bit - set in x with x in the range 1 < x < 0x00000200. This form is - used so that locals within fi can be bytes rather than words -*/ - -static uint_8t hibit(const uint_32t x) -{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -/* return the inverse of the finite field element x */ - -static uint_8t gf_inv(const uint_8t x) -{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if(x < 2) - return x; - - for( ; ; ) - { - if(n1) - while(n2 >= n1) /* divide polynomial p2 by p1 */ - { - n2 /= n1; /* shift smaller polynomial left */ - p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= v1 * n2; /* shift accumulated value and */ - n2 = hibit(p2); /* add into result */ - } - else - return v1; - - if(n2) /* repeat with values swapped */ - while(n1 >= n2) - { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; - n1 = hibit(p1); - } - else - return v2; - } -} - -#endif - -/* The forward and inverse affine transformations used in the S-box */ -uint_8t fwd_affine(const uint_8t x) -{ uint_32t w = x; - w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); - return 0x63 ^ ((w ^ (w >> 8)) & 0xff); -} - -uint_8t inv_affine(const uint_8t x) -{ uint_32t w = x; - w = (w << 1) ^ (w << 3) ^ (w << 6); - return 0x05 ^ ((w ^ (w >> 8)) & 0xff); -} - -static int init = 0; - -AES_RETURN aes_init(void) -{ uint_32t i, w; - -#if defined(FF_TABLES) - - uint_8t pow[512], log[256]; - - if(init) - return EXIT_SUCCESS; - /* log and power tables for GF(2^8) finite field with - WPOLY as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables - */ - - i = 0; w = 1; - do - { - pow[i] = (uint_8t)w; - pow[i + 255] = (uint_8t)w; - log[w] = (uint_8t)i++; - w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); - } - while (w != 1); - -#else - if(init) - return EXIT_SUCCESS; -#endif - - for(i = 0, w = 1; i < RC_LENGTH; ++i) - { - t_set(r,c)[i] = bytes2word(w, 0, 0, 0); - w = f2(w); - } - - for(i = 0; i < 256; ++i) - { uint_8t b; - - b = fwd_affine(gf_inv((uint_8t)i)); - w = bytes2word(f2(b), b, b, f3(b)); - -#if defined( SBX_SET ) - t_set(s,box)[i] = b; -#endif - -#if defined( FT1_SET ) /* tables for a normal encryption round */ - t_set(f,n)[i] = w; -#endif -#if defined( FT4_SET ) - t_set(f,n)[0][i] = w; - t_set(f,n)[1][i] = upr(w,1); - t_set(f,n)[2][i] = upr(w,2); - t_set(f,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); - -#if defined( FL1_SET ) /* tables for last encryption round (may also */ - t_set(f,l)[i] = w; /* be used in the key schedule) */ -#endif -#if defined( FL4_SET ) - t_set(f,l)[0][i] = w; - t_set(f,l)[1][i] = upr(w,1); - t_set(f,l)[2][i] = upr(w,2); - t_set(f,l)[3][i] = upr(w,3); -#endif - -#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ - t_set(l,s)[i] = w; /* not of the required form */ -#endif -#if defined( LS4_SET ) - t_set(l,s)[0][i] = w; - t_set(l,s)[1][i] = upr(w,1); - t_set(l,s)[2][i] = upr(w,2); - t_set(l,s)[3][i] = upr(w,3); -#endif - - b = gf_inv(inv_affine((uint_8t)i)); - w = bytes2word(fe(b), f9(b), fd(b), fb(b)); - -#if defined( IM1_SET ) /* tables for the inverse mix column operation */ - t_set(i,m)[b] = w; -#endif -#if defined( IM4_SET ) - t_set(i,m)[0][b] = w; - t_set(i,m)[1][b] = upr(w,1); - t_set(i,m)[2][b] = upr(w,2); - t_set(i,m)[3][b] = upr(w,3); -#endif - -#if defined( ISB_SET ) - t_set(i,box)[i] = b; -#endif -#if defined( IT1_SET ) /* tables for a normal decryption round */ - t_set(i,n)[i] = w; -#endif -#if defined( IT4_SET ) - t_set(i,n)[0][i] = w; - t_set(i,n)[1][i] = upr(w,1); - t_set(i,n)[2][i] = upr(w,2); - t_set(i,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); -#if defined( IL1_SET ) /* tables for last decryption round */ - t_set(i,l)[i] = w; -#endif -#if defined( IL4_SET ) - t_set(i,l)[0][i] = w; - t_set(i,l)[1][i] = upr(w,1); - t_set(i,l)[2][i] = upr(w,2); - t_set(i,l)[3][i] = upr(w,3); -#endif - } - init = 1; - return EXIT_SUCCESS; -} - -#endif - -#if defined(__cplusplus) -} -#endif - +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#define DO_TABLES + +#include "aes.h" +#include "aesopt.h" + +#if defined(FIXED_TABLES) + +#define sb_data(w) {\ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) {\ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) {\ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +#define rc_data(w) {\ + w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ + w(0x1b), w(0x36) } + +#define h0(x) (x) + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +#endif + +#if defined(FIXED_TABLES) || !defined(FF_TABLES) + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#else + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) + +#endif + +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined(FIXED_TABLES) + +/* implemented in case of wrong call for fixed tables */ + +AES_RETURN aes_init(void) +{ + return EXIT_SUCCESS; +} + +#else /* Generate the tables for the dynamic table option */ + +#if defined(FF_TABLES) + +#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) + +#else + +/* It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static uint_8t hibit(const uint_32t x) +{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint_8t gf_inv(const uint_8t x) +{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) + return x; + + for( ; ; ) + { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= v1 * n2; /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } +} + +#endif + +/* The forward and inverse affine transformations used in the S-box */ +uint_8t fwd_affine(const uint_8t x) +{ uint_32t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +} + +uint_8t inv_affine(const uint_8t x) +{ uint_32t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +} + +static int init = 0; + +AES_RETURN aes_init(void) +{ uint_32t i, w; + +#if defined(FF_TABLES) + + uint_8t pow[512], log[256]; + + if(init) + return EXIT_SUCCESS; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (uint_8t)w; + pow[i + 255] = (uint_8t)w; + log[w] = (uint_8t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); + +#else + if(init) + return EXIT_SUCCESS; +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + t_set(r,c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) + { uint_8t b; + + b = fwd_affine(gf_inv((uint_8t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#if defined( SBX_SET ) + t_set(s,box)[i] = b; +#endif + +#if defined( FT1_SET ) /* tables for a normal encryption round */ + t_set(f,n)[i] = w; +#endif +#if defined( FT4_SET ) + t_set(f,n)[0][i] = w; + t_set(f,n)[1][i] = upr(w,1); + t_set(f,n)[2][i] = upr(w,2); + t_set(f,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); + +#if defined( FL1_SET ) /* tables for last encryption round (may also */ + t_set(f,l)[i] = w; /* be used in the key schedule) */ +#endif +#if defined( FL4_SET ) + t_set(f,l)[0][i] = w; + t_set(f,l)[1][i] = upr(w,1); + t_set(f,l)[2][i] = upr(w,2); + t_set(f,l)[3][i] = upr(w,3); +#endif + +#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ + t_set(l,s)[i] = w; /* not of the required form */ +#endif +#if defined( LS4_SET ) + t_set(l,s)[0][i] = w; + t_set(l,s)[1][i] = upr(w,1); + t_set(l,s)[2][i] = upr(w,2); + t_set(l,s)[3][i] = upr(w,3); +#endif + + b = gf_inv(inv_affine((uint_8t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#if defined( IM1_SET ) /* tables for the inverse mix column operation */ + t_set(i,m)[b] = w; +#endif +#if defined( IM4_SET ) + t_set(i,m)[0][b] = w; + t_set(i,m)[1][b] = upr(w,1); + t_set(i,m)[2][b] = upr(w,2); + t_set(i,m)[3][b] = upr(w,3); +#endif + +#if defined( ISB_SET ) + t_set(i,box)[i] = b; +#endif +#if defined( IT1_SET ) /* tables for a normal decryption round */ + t_set(i,n)[i] = w; +#endif +#if defined( IT4_SET ) + t_set(i,n)[0][i] = w; + t_set(i,n)[1][i] = upr(w,1); + t_set(i,n)[2][i] = upr(w,2); + t_set(i,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); +#if defined( IL1_SET ) /* tables for last decryption round */ + t_set(i,l)[i] = w; +#endif +#if defined( IL4_SET ) + t_set(i,l)[0][i] = w; + t_set(i,l)[1][i] = upr(w,1); + t_set(i,l)[2][i] = upr(w,2); + t_set(i,l)[3][i] = upr(w,3); +#endif + } + init = 1; + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif + diff --git a/libs/minizip/source/aes/aestab.h b/libs/minizip/source/aes/aestab.h index de685679..21fc7361 100644 --- a/libs/minizip/source/aes/aestab.h +++ b/libs/minizip/source/aes/aestab.h @@ -1,173 +1,173 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the code for declaring the tables needed to implement - AES. The file aesopt.h is assumed to be included before this header file. - If there are no global variables, the definitions here can be used to put - the AES tables in a structure so that a pointer can then be added to the - AES context to pass them to the AES routines that need them. If this - facility is used, the calling program has to ensure that this pointer is - managed appropriately. In particular, the value of the t_dec(in,it) item - in the table structure must be set to zero in order to ensure that the - tables are initialised. In practice the three code sequences in aeskey.c - that control the calls to aes_init() and the aes_init() routine itself will - have to be changed for a specific implementation. If global variables are - available it will generally be preferable to use them with the precomputed - FIXED_TABLES option that uses static global tables. - - The following defines can be used to control the way the tables - are defined, initialised and used in embedded environments that - require special features for these purposes - - the 't_dec' construction is used to declare fixed table arrays - the 't_set' construction is used to set fixed table values - the 't_use' construction is used to access fixed table values - - 256 byte tables: - - t_xxx(s,box) => forward S box - t_xxx(i,box) => inverse S box - - 256 32-bit word OR 4 x 256 32-bit word tables: - - t_xxx(f,n) => forward normal round - t_xxx(f,l) => forward last round - t_xxx(i,n) => inverse normal round - t_xxx(i,l) => inverse last round - t_xxx(l,s) => key schedule table - t_xxx(i,m) => key schedule table - - Other variables and tables: - - t_xxx(r,c) => the rcon table -*/ - -#if !defined( _AESTAB_H ) -#define _AESTAB_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#define t_dec(m,n) t_##m##n -#define t_set(m,n) t_##m##n -#define t_use(m,n) t_##m##n - -#if defined(FIXED_TABLES) -# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) -/* make tables far data to avoid using too much DGROUP space (PG) */ -# define CONST const far -# else -# define CONST const -# endif -#else -# define CONST -#endif - -#if defined(DO_TABLES) -# define EXTERN -#else -# define EXTERN extern -#endif - -#if defined(_MSC_VER) && defined(TABLE_ALIGN) -#define ALIGN __declspec(align(TABLE_ALIGN)) -#else -#define ALIGN -#endif - -#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) -# define XP_DIR __cdecl -#else -# define XP_DIR -#endif - -#if defined(DO_TABLES) && defined(FIXED_TABLES) -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } -EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0); -#else -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] -EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH]; -#endif - -#if defined( SBX_SET ) - d_1(uint_8t, t_dec(s,box), sb_data, h0); -#endif -#if defined( ISB_SET ) - d_1(uint_8t, t_dec(i,box), isb_data, h0); -#endif - -#if defined( FT1_SET ) - d_1(uint_32t, t_dec(f,n), sb_data, u0); -#endif -#if defined( FT4_SET ) - d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3); -#endif - -#if defined( FL1_SET ) - d_1(uint_32t, t_dec(f,l), sb_data, w0); -#endif -#if defined( FL4_SET ) - d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3); -#endif - -#if defined( IT1_SET ) - d_1(uint_32t, t_dec(i,n), isb_data, v0); -#endif -#if defined( IT4_SET ) - d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3); -#endif - -#if defined( IL1_SET ) - d_1(uint_32t, t_dec(i,l), isb_data, w0); -#endif -#if defined( IL4_SET ) - d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3); -#endif - -#if defined( LS1_SET ) -#if defined( FL1_SET ) -#undef LS1_SET -#else - d_1(uint_32t, t_dec(l,s), sb_data, w0); -#endif -#endif - -#if defined( LS4_SET ) -#if defined( FL4_SET ) -#undef LS4_SET -#else - d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3); -#endif -#endif - -#if defined( IM1_SET ) - d_1(uint_32t, t_dec(i,m), mm_data, v0); -#endif -#if defined( IM4_SET ) - d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3); -#endif - -#if defined(__cplusplus) -} -#endif - -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + This file contains the code for declaring the tables needed to implement + AES. The file aesopt.h is assumed to be included before this header file. + If there are no global variables, the definitions here can be used to put + the AES tables in a structure so that a pointer can then be added to the + AES context to pass them to the AES routines that need them. If this + facility is used, the calling program has to ensure that this pointer is + managed appropriately. In particular, the value of the t_dec(in,it) item + in the table structure must be set to zero in order to ensure that the + tables are initialised. In practice the three code sequences in aeskey.c + that control the calls to aes_init() and the aes_init() routine itself will + have to be changed for a specific implementation. If global variables are + available it will generally be preferable to use them with the precomputed + FIXED_TABLES option that uses static global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#if !defined( _AESTAB_H ) +#define _AESTAB_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define t_dec(m,n) t_##m##n +#define t_set(m,n) t_##m##n +#define t_use(m,n) t_##m##n + +#if defined(FIXED_TABLES) +# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) +/* make tables far data to avoid using too much DGROUP space (PG) */ +# define CONST const far +# else +# define CONST const +# endif +#else +# define CONST +#endif + +#if defined(DO_TABLES) +# define EXTERN +#else +# define EXTERN extern +#endif + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define ALIGN __declspec(align(TABLE_ALIGN)) +#else +#define ALIGN +#endif + +#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) +# define XP_DIR __cdecl +#else +# define XP_DIR +#endif + +#if defined(DO_TABLES) && defined(FIXED_TABLES) +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } +EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0); +#else +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] +EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH]; +#endif + +#if defined( SBX_SET ) + d_1(uint_8t, t_dec(s,box), sb_data, h0); +#endif +#if defined( ISB_SET ) + d_1(uint_8t, t_dec(i,box), isb_data, h0); +#endif + +#if defined( FT1_SET ) + d_1(uint_32t, t_dec(f,n), sb_data, u0); +#endif +#if defined( FT4_SET ) + d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3); +#endif + +#if defined( FL1_SET ) + d_1(uint_32t, t_dec(f,l), sb_data, w0); +#endif +#if defined( FL4_SET ) + d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3); +#endif + +#if defined( IT1_SET ) + d_1(uint_32t, t_dec(i,n), isb_data, v0); +#endif +#if defined( IT4_SET ) + d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3); +#endif + +#if defined( IL1_SET ) + d_1(uint_32t, t_dec(i,l), isb_data, w0); +#endif +#if defined( IL4_SET ) + d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3); +#endif + +#if defined( LS1_SET ) +#if defined( FL1_SET ) +#undef LS1_SET +#else + d_1(uint_32t, t_dec(l,s), sb_data, w0); +#endif +#endif + +#if defined( LS4_SET ) +#if defined( FL4_SET ) +#undef LS4_SET +#else + d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3); +#endif +#endif + +#if defined( IM1_SET ) + d_1(uint_32t, t_dec(i,m), mm_data, v0); +#endif +#if defined( IM4_SET ) + d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/brg_endian.h b/libs/minizip/source/aes/brg_endian.h index 0f12fbbf..82e48f0b 100644 --- a/libs/minizip/source/aes/brg_endian.h +++ b/libs/minizip/source/aes/brg_endian.h @@ -1,126 +1,126 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#ifndef _BRG_ENDIAN_H -#define _BRG_ENDIAN_H - -#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ -#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ - -/* Include files where endian defines and byteswap functions may reside */ -#if defined( __sun ) -# include -#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) -# include -#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ - defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) -# include -#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) -# if !defined( __MINGW32__ ) && !defined( _AIX ) -# include -# if !defined( __BEOS__ ) -# include -# endif -# endif -#endif - -/* Now attempt to set the define for platform byte order using any */ -/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ -/* seem to encompass most endian symbol definitions */ - -#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) -# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) -# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( _BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( _LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) -# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) -# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -/* if the platform byte order could not be determined, then try to */ -/* set this define using common machine defines */ -#if !defined(PLATFORM_BYTE_ORDER) - -#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ - defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ - defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ - defined( vax ) || defined( vms ) || defined( VMS ) || \ - defined( __VMS ) || defined( _M_X64 ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN - -#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ - defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ - defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ - defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ - defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ - defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ - defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN - -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order -#endif - -#endif - -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +*/ + +#ifndef _BRG_ENDIAN_H +#define _BRG_ENDIAN_H + +#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ +#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ + +/* Include files where endian defines and byteswap functions may reside */ +#if defined( __sun ) +# include +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff --git a/libs/minizip/source/aes/brg_types.h b/libs/minizip/source/aes/brg_types.h index a1d7483a..40d4af5b 100644 --- a/libs/minizip/source/aes/brg_types.h +++ b/libs/minizip/source/aes/brg_types.h @@ -1,219 +1,219 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - The unsigned integer types defined here are of the form uint_t where - is the length of the type; for example, the unsigned 32-bit type is - 'uint_32t'. These are NOT the same as the 'C99 integer types' that are - defined in the inttypes.h and stdint.h headers since attempts to use these - types have shown that support for them is still highly variable. However, - since the latter are of the form uint_t, a regular expression search - and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') - can be used to convert the types used here to the C99 standard types. -*/ - -#ifndef _BRG_TYPES_H -#define _BRG_TYPES_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#include - -#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# include -# define ptrint_t intptr_t -#elif defined( __ECOS__ ) -# define intptr_t unsigned int -# define ptrint_t intptr_t -#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) -# include -# define ptrint_t intptr_t -#else -# define ptrint_t int -#endif - -#ifndef BRG_UI8 -# define BRG_UI8 -# if UCHAR_MAX == 255u - typedef unsigned char uint_8t; -# else -# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI16 -# define BRG_UI16 -# if USHRT_MAX == 65535u - typedef unsigned short uint_16t; -# else -# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h -# endif -#endif - -#ifndef BRG_UI32 -# define BRG_UI32 -# if UINT_MAX == 4294967295u -# define li_32(h) 0x##h##u - typedef unsigned int uint_32t; -# elif ULONG_MAX == 4294967295u -# define li_32(h) 0x##h##ul - typedef unsigned long uint_32t; -# elif defined( _CRAY ) -# error This code needs 32-bit data types, which Cray machines do not provide -# else -# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI64 -# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 - typedef unsigned __int64 uint_64t; -# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 - typedef unsigned __int64 uint_64t; -# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# elif defined( __MVS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned int long long uint_64t; -# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u -# if UINT_MAX == 18446744073709551615u -# define BRG_UI64 -# define li_64(h) 0x##h##u - typedef unsigned int uint_64t; -# endif -# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u -# if ULONG_MAX == 18446744073709551615ul -# define BRG_UI64 -# define li_64(h) 0x##h##ul - typedef unsigned long uint_64t; -# endif -# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u -# if ULLONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# endif -# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u -# if ULONG_LONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# endif -# endif -#endif - -#if !defined( BRG_UI64 ) -# if defined( NEED_UINT_64T ) -# error Please define uint_64t as an unsigned 64 bit type in brg_types.h -# endif -#endif - -#ifndef RETURN_VALUES -# define RETURN_VALUES -# if defined( DLL_EXPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllexport ) void __stdcall -# define INT_RETURN __declspec( dllexport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllexport__ ) void -# define INT_RETURN __declspec( __dllexport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( DLL_IMPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllimport ) void __stdcall -# define INT_RETURN __declspec( dllimport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllimport__ ) void -# define INT_RETURN __declspec( __dllimport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( __WATCOMC__ ) -# define VOID_RETURN void __cdecl -# define INT_RETURN int __cdecl -# else -# define VOID_RETURN void -# define INT_RETURN int -# endif -#endif - -/* These defines are used to detect and set the memory alignment of pointers. - Note that offsets are in bytes. - - ALIGN_OFFSET(x,n) return the positive or zero offset of - the memory addressed by the pointer 'x' - from an address that is aligned on an - 'n' byte boundary ('n' is a power of 2) - - ALIGN_FLOOR(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not higher than the memory address - pointed to by 'x' ('n' is a power of 2) - - ALIGN_CEIL(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not lower than the memory address - pointed to by 'x' ('n' is a power of 2) -*/ - -#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) - -/* These defines are used to declare buffers in a way that allows - faster operations on longer variables to be used. In all these - defines 'size' must be a power of 2 and >= 8. NOTE that the - buffer size is in bytes but the type length is in bits - - UNIT_TYPEDEF(x,size) declares a variable 'x' of length - 'size' bits - - BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' - bytes defined as an array of variables - each of 'size' bits (bsize must be a - multiple of size / 8) - - UNIT_CAST(x,size) casts a variable to a type of - length 'size' bits - - UPTR_CAST(x,size) casts a pointer to a pointer to a - varaiable of length 'size' bits -*/ - -#define UI_TYPE(size) uint_##size##t -#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x -#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] -#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) -#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) - -#if defined(__cplusplus) -} -#endif - -#endif +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 + + The unsigned integer types defined here are of the form uint_t where + is the length of the type; for example, the unsigned 32-bit type is + 'uint_32t'. These are NOT the same as the 'C99 integer types' that are + defined in the inttypes.h and stdint.h headers since attempts to use these + types have shown that support for them is still highly variable. However, + since the latter are of the form uint_t, a regular expression search + and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') + can be used to convert the types used here to the C99 standard types. +*/ + +#ifndef _BRG_TYPES_H +#define _BRG_TYPES_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# include +# define ptrint_t intptr_t +#elif defined( __ECOS__ ) +# define intptr_t unsigned int +# define ptrint_t intptr_t +#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) +# include +# define ptrint_t intptr_t +#else +# define ptrint_t int +#endif + +#ifndef BRG_UI8 +# define BRG_UI8 +# if UCHAR_MAX == 255u + typedef unsigned char uint_8t; +# else +# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI16 +# define BRG_UI16 +# if USHRT_MAX == 65535u + typedef unsigned short uint_16t; +# else +# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h +# endif +#endif + +#ifndef BRG_UI32 +# define BRG_UI32 +# if UINT_MAX == 4294967295u +# define li_32(h) 0x##h##u + typedef unsigned int uint_32t; +# elif ULONG_MAX == 4294967295u +# define li_32(h) 0x##h##ul + typedef unsigned long uint_32t; +# elif defined( _CRAY ) +# error This code needs 32-bit data types, which Cray machines do not provide +# else +# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI64 +# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 + typedef unsigned __int64 uint_64t; +# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 + typedef unsigned __int64 uint_64t; +# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# elif defined( __MVS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned int long long uint_64t; +# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u +# if UINT_MAX == 18446744073709551615u +# define BRG_UI64 +# define li_64(h) 0x##h##u + typedef unsigned int uint_64t; +# endif +# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u +# if ULONG_MAX == 18446744073709551615ul +# define BRG_UI64 +# define li_64(h) 0x##h##ul + typedef unsigned long uint_64t; +# endif +# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u +# if ULLONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# endif +# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u +# if ULONG_LONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# endif +# endif +#endif + +#if !defined( BRG_UI64 ) +# if defined( NEED_UINT_64T ) +# error Please define uint_64t as an unsigned 64 bit type in brg_types.h +# endif +#endif + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to detect and set the memory alignment of pointers. + Note that offsets are in bytes. + + ALIGN_OFFSET(x,n) return the positive or zero offset of + the memory addressed by the pointer 'x' + from an address that is aligned on an + 'n' byte boundary ('n' is a power of 2) + + ALIGN_FLOOR(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not higher than the memory address + pointed to by 'x' ('n' is a power of 2) + + ALIGN_CEIL(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not lower than the memory address + pointed to by 'x' ('n' is a power of 2) +*/ + +#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8. NOTE that the + buffer size is in bytes but the type length is in bits + + UNIT_TYPEDEF(x,size) declares a variable 'x' of length + 'size' bits + + BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + UNIT_CAST(x,size) casts a variable to a type of + length 'size' bits + + UPTR_CAST(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define UI_TYPE(size) uint_##size##t +#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x +#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] +#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) +#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/entropy.c b/libs/minizip/source/aes/entropy.c index c37cc1ca..37f3a174 100644 --- a/libs/minizip/source/aes/entropy.c +++ b/libs/minizip/source/aes/entropy.c @@ -1,53 +1,53 @@ -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#ifdef _WIN32 -int entropy_fun(unsigned char buf[], unsigned int len) -{ - HCRYPTPROV provider; - unsigned __int64 pentium_tsc[1]; - unsigned int i; - int result = 0; - - - if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - { - result = CryptGenRandom(provider, len, buf); - CryptReleaseContext(provider, 0); - if (result) - return len; - } - - QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc); - - for(i = 0; i < 8 && i < len; ++i) - buf[i] = ((unsigned char*)pentium_tsc)[i]; - - return i; -} -#else -int entropy_fun(unsigned char buf[], unsigned int len) -{ - int frand = open("/dev/random", O_RDONLY); - int rlen = 0; - if (frand != -1) - { - rlen = read(frand, buf, len); - close(frand); - } - return rlen; -} -#endif - -#if defined(__cplusplus) -} -#endif +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#ifdef _WIN32 +int entropy_fun(unsigned char buf[], unsigned int len) +{ + HCRYPTPROV provider; + unsigned __int64 pentium_tsc[1]; + unsigned int i; + int result = 0; + + + if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + result = CryptGenRandom(provider, len, buf); + CryptReleaseContext(provider, 0); + if (result) + return len; + } + + QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc); + + for(i = 0; i < 8 && i < len; ++i) + buf[i] = ((unsigned char*)pentium_tsc)[i]; + + return i; +} +#else +int entropy_fun(unsigned char buf[], unsigned int len) +{ + int frand = open("/dev/random", O_RDONLY); + int rlen = 0; + if (frand != -1) + { + rlen = read(frand, buf, len); + close(frand); + } + return rlen; +} +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/entropy.h b/libs/minizip/source/aes/entropy.h index 34d59d2b..3a5fe9af 100644 --- a/libs/minizip/source/aes/entropy.h +++ b/libs/minizip/source/aes/entropy.h @@ -1,16 +1,16 @@ - -#ifndef _ENTROPY_FUN_H -#define _ENTROPY_FUN_H - -#if defined(__cplusplus) -extern "C" -{ -#endif - -int entropy_fun(unsigned char buf[], unsigned int len); - -#if defined(__cplusplus) -} -#endif - -#endif + +#ifndef _ENTROPY_FUN_H +#define _ENTROPY_FUN_H + +#if defined(__cplusplus) +extern "C" +{ +#endif + +int entropy_fun(unsigned char buf[], unsigned int len); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/fileenc.c b/libs/minizip/source/aes/fileenc.c index 1533dd08..750b9351 100644 --- a/libs/minizip/source/aes/fileenc.c +++ b/libs/minizip/source/aes/fileenc.c @@ -1,143 +1,143 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - ------------------------------------------------------------------------- - Issue Date: 24/01/2003 - - This file implements password based file encryption and authentication - using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password - based key derivation. - -*/ - -#include - -#include "fileenc.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* subroutine for data encryption/decryption */ -/* this could be speeded up a lot by aligning */ -/* buffers and using 32 bit operations */ - -static void encr_data(unsigned char data[], unsigned long d_len, fcrypt_ctx cx[1]) -{ unsigned long i = 0, pos = cx->encr_pos; - - while(i < d_len) - { - if(pos == AES_BLOCK_SIZE) - { unsigned int j = 0; - /* increment encryption nonce */ - while(j < 8 && !++cx->nonce[j]) - ++j; - /* encrypt the nonce to form next xor buffer */ - aes_encrypt(cx->nonce, cx->encr_bfr, cx->encr_ctx); - pos = 0; - } - - data[i++] ^= cx->encr_bfr[pos++]; - } - - cx->encr_pos = pos; -} - -int fcrypt_init( - int mode, /* the mode to be used (input) */ - const unsigned char pwd[], /* the user specified password (input) */ - unsigned int pwd_len, /* the length of the password (input) */ - const unsigned char salt[], /* the salt (input) */ -#ifdef PASSWORD_VERIFIER - unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ -#endif - fcrypt_ctx cx[1]) /* the file encryption context (output) */ -{ unsigned char kbuf[2 * MAX_KEY_LENGTH + PWD_VER_LENGTH]; - - if(pwd_len > MAX_PWD_LENGTH) - return PASSWORD_TOO_LONG; - - if(mode < 1 || mode > 3) - return BAD_MODE; - - cx->mode = mode; - cx->pwd_len = pwd_len; - - /* derive the encryption and authentication keys and the password verifier */ - derive_key(pwd, pwd_len, salt, SALT_LENGTH(mode), KEYING_ITERATIONS, - kbuf, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH); - - /* initialise the encryption nonce and buffer pos */ - cx->encr_pos = AES_BLOCK_SIZE; - /* if we need a random component in the encryption */ - /* nonce, this is where it would have to be set */ - memset(cx->nonce, 0, AES_BLOCK_SIZE * sizeof(unsigned char)); - - /* initialise for encryption using key 1 */ - aes_encrypt_key(kbuf, KEY_LENGTH(mode), cx->encr_ctx); - - /* initialise for authentication using key 2 */ - hmac_sha_begin(cx->auth_ctx); - hmac_sha_key(kbuf + KEY_LENGTH(mode), KEY_LENGTH(mode), cx->auth_ctx); - -#ifdef PASSWORD_VERIFIER - memcpy(pwd_ver, kbuf + 2 * KEY_LENGTH(mode), PWD_VER_LENGTH); -#endif - - return GOOD_RETURN; -} - -/* perform 'in place' encryption and authentication */ - -void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) -{ - encr_data(data, data_len, cx); - hmac_sha_data(data, data_len, cx->auth_ctx); -} - -/* perform 'in place' authentication and decryption */ - -void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) -{ - hmac_sha_data(data, data_len, cx->auth_ctx); - encr_data(data, data_len, cx); -} - -/* close encryption/decryption and return the MAC value */ - -int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1]) -{ - hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx); - return MAC_LENGTH(cx->mode); /* return MAC length in bytes */ -} - -#if defined(__cplusplus) -} -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This file implements password based file encryption and authentication + using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password + based key derivation. + +*/ + +#include + +#include "fileenc.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* subroutine for data encryption/decryption */ +/* this could be speeded up a lot by aligning */ +/* buffers and using 32 bit operations */ + +static void encr_data(unsigned char data[], unsigned long d_len, fcrypt_ctx cx[1]) +{ unsigned long i = 0, pos = cx->encr_pos; + + while(i < d_len) + { + if(pos == AES_BLOCK_SIZE) + { unsigned int j = 0; + /* increment encryption nonce */ + while(j < 8 && !++cx->nonce[j]) + ++j; + /* encrypt the nonce to form next xor buffer */ + aes_encrypt(cx->nonce, cx->encr_bfr, cx->encr_ctx); + pos = 0; + } + + data[i++] ^= cx->encr_bfr[pos++]; + } + + cx->encr_pos = pos; +} + +int fcrypt_init( + int mode, /* the mode to be used (input) */ + const unsigned char pwd[], /* the user specified password (input) */ + unsigned int pwd_len, /* the length of the password (input) */ + const unsigned char salt[], /* the salt (input) */ +#ifdef PASSWORD_VERIFIER + unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ +#endif + fcrypt_ctx cx[1]) /* the file encryption context (output) */ +{ unsigned char kbuf[2 * MAX_KEY_LENGTH + PWD_VER_LENGTH]; + + if(pwd_len > MAX_PWD_LENGTH) + return PASSWORD_TOO_LONG; + + if(mode < 1 || mode > 3) + return BAD_MODE; + + cx->mode = mode; + cx->pwd_len = pwd_len; + + /* derive the encryption and authentication keys and the password verifier */ + derive_key(pwd, pwd_len, salt, SALT_LENGTH(mode), KEYING_ITERATIONS, + kbuf, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH); + + /* initialise the encryption nonce and buffer pos */ + cx->encr_pos = AES_BLOCK_SIZE; + /* if we need a random component in the encryption */ + /* nonce, this is where it would have to be set */ + memset(cx->nonce, 0, AES_BLOCK_SIZE * sizeof(unsigned char)); + + /* initialise for encryption using key 1 */ + aes_encrypt_key(kbuf, KEY_LENGTH(mode), cx->encr_ctx); + + /* initialise for authentication using key 2 */ + hmac_sha_begin(cx->auth_ctx); + hmac_sha_key(kbuf + KEY_LENGTH(mode), KEY_LENGTH(mode), cx->auth_ctx); + +#ifdef PASSWORD_VERIFIER + memcpy(pwd_ver, kbuf + 2 * KEY_LENGTH(mode), PWD_VER_LENGTH); +#endif + + return GOOD_RETURN; +} + +/* perform 'in place' encryption and authentication */ + +void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) +{ + encr_data(data, data_len, cx); + hmac_sha_data(data, data_len, cx->auth_ctx); +} + +/* perform 'in place' authentication and decryption */ + +void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) +{ + hmac_sha_data(data, data_len, cx->auth_ctx); + encr_data(data, data_len, cx); +} + +/* close encryption/decryption and return the MAC value */ + +int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1]) +{ + hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx); + return MAC_LENGTH(cx->mode); /* return MAC length in bytes */ +} + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/fileenc.h b/libs/minizip/source/aes/fileenc.h index 9c0250ed..ba64a7c3 100644 --- a/libs/minizip/source/aes/fileenc.h +++ b/libs/minizip/source/aes/fileenc.h @@ -1,121 +1,121 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 24/01/2003 - - This file contains the header file for fileenc.c, which implements password - based file encryption and authentication using AES in CTR mode, HMAC-SHA1 - authentication and RFC2898 password based key derivation. -*/ - -#ifndef _FENC_H -#define _FENC_H - -#include "aes.h" -#include "hmac.h" -#include "pwd2key.h" - -#define PASSWORD_VERIFIER - -#define MAX_KEY_LENGTH 32 -#define MAX_PWD_LENGTH 128 -#define MAX_SALT_LENGTH 16 -#define KEYING_ITERATIONS 1000 - -#ifdef PASSWORD_VERIFIER -#define PWD_VER_LENGTH 2 -#else -#define PWD_VER_LENGTH 0 -#endif - -#define GOOD_RETURN 0 -#define PASSWORD_TOO_LONG -100 -#define BAD_MODE -101 - -/* - Field lengths (in bytes) versus File Encryption Mode (0 < mode < 4) - - Mode Key Salt MAC Overhead - 1 16 8 10 18 - 2 24 12 10 22 - 3 32 16 10 26 - - The following macros assume that the mode value is correct. -*/ - -#define KEY_LENGTH(mode) (8 * (mode & 3) + 8) -#define SALT_LENGTH(mode) (4 * (mode & 3) + 4) -#define MAC_LENGTH(mode) (10) - -/* the context for file encryption */ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -typedef struct -{ unsigned char nonce[AES_BLOCK_SIZE]; /* the CTR nonce */ - unsigned char encr_bfr[AES_BLOCK_SIZE]; /* encrypt buffer */ - aes_encrypt_ctx encr_ctx[1]; /* encryption context */ - hmac_ctx auth_ctx[1]; /* authentication context */ - unsigned int encr_pos; /* block position (enc) */ - unsigned int pwd_len; /* password length */ - unsigned int mode; /* File encryption mode */ -} fcrypt_ctx; - -/* initialise file encryption or decryption */ - -int fcrypt_init( - int mode, /* the mode to be used (input) */ - const unsigned char pwd[], /* the user specified password (input) */ - unsigned int pwd_len, /* the length of the password (input) */ - const unsigned char salt[], /* the salt (input) */ -#ifdef PASSWORD_VERIFIER - unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ -#endif - fcrypt_ctx cx[1]); /* the file encryption context (output) */ - -/* perform 'in place' encryption or decryption and authentication */ - -void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); -void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); - -/* close encryption/decryption and return the MAC value */ -/* the return value is the length of the MAC */ - -int fcrypt_end(unsigned char mac[], /* the MAC value (output) */ - fcrypt_ctx cx[1]); /* the context (input) */ - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This file contains the header file for fileenc.c, which implements password + based file encryption and authentication using AES in CTR mode, HMAC-SHA1 + authentication and RFC2898 password based key derivation. +*/ + +#ifndef _FENC_H +#define _FENC_H + +#include "aes.h" +#include "hmac.h" +#include "pwd2key.h" + +#define PASSWORD_VERIFIER + +#define MAX_KEY_LENGTH 32 +#define MAX_PWD_LENGTH 128 +#define MAX_SALT_LENGTH 16 +#define KEYING_ITERATIONS 1000 + +#ifdef PASSWORD_VERIFIER +#define PWD_VER_LENGTH 2 +#else +#define PWD_VER_LENGTH 0 +#endif + +#define GOOD_RETURN 0 +#define PASSWORD_TOO_LONG -100 +#define BAD_MODE -101 + +/* + Field lengths (in bytes) versus File Encryption Mode (0 < mode < 4) + + Mode Key Salt MAC Overhead + 1 16 8 10 18 + 2 24 12 10 22 + 3 32 16 10 26 + + The following macros assume that the mode value is correct. +*/ + +#define KEY_LENGTH(mode) (8 * (mode & 3) + 8) +#define SALT_LENGTH(mode) (4 * (mode & 3) + 4) +#define MAC_LENGTH(mode) (10) + +/* the context for file encryption */ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +typedef struct +{ unsigned char nonce[AES_BLOCK_SIZE]; /* the CTR nonce */ + unsigned char encr_bfr[AES_BLOCK_SIZE]; /* encrypt buffer */ + aes_encrypt_ctx encr_ctx[1]; /* encryption context */ + hmac_ctx auth_ctx[1]; /* authentication context */ + unsigned int encr_pos; /* block position (enc) */ + unsigned int pwd_len; /* password length */ + unsigned int mode; /* File encryption mode */ +} fcrypt_ctx; + +/* initialise file encryption or decryption */ + +int fcrypt_init( + int mode, /* the mode to be used (input) */ + const unsigned char pwd[], /* the user specified password (input) */ + unsigned int pwd_len, /* the length of the password (input) */ + const unsigned char salt[], /* the salt (input) */ +#ifdef PASSWORD_VERIFIER + unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ +#endif + fcrypt_ctx cx[1]); /* the file encryption context (output) */ + +/* perform 'in place' encryption or decryption and authentication */ + +void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); +void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); + +/* close encryption/decryption and return the MAC value */ +/* the return value is the length of the MAC */ + +int fcrypt_end(unsigned char mac[], /* the MAC value (output) */ + fcrypt_ctx cx[1]); /* the context (input) */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/hmac.c b/libs/minizip/source/aes/hmac.c index 7600a4e4..c71b14ea 100644 --- a/libs/minizip/source/aes/hmac.c +++ b/libs/minizip/source/aes/hmac.c @@ -1,145 +1,145 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 26/08/2003 - - This is an implementation of HMAC, the FIPS standard keyed hash function -*/ - -#include "hmac.h" -#include "brg_types.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* initialise the HMAC context to zero */ -void hmac_sha_begin(hmac_ctx cx[1]) -{ - memset(cx, 0, sizeof(hmac_ctx)); -} - -/* input the HMAC key (can be called multiple times) */ -int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]) -{ - if(cx->klen == HMAC_IN_DATA) /* error if further key input */ - return HMAC_BAD_MODE; /* is attempted in data mode */ - - if(cx->klen + key_len > HASH_INPUT_SIZE) /* if the key has to be hashed */ - { - if(cx->klen <= HASH_INPUT_SIZE) /* if the hash has not yet been */ - { /* started, initialise it and */ - sha_begin(cx->ctx); /* hash stored key characters */ - sha_hash(cx->key, cx->klen, cx->ctx); - } - - sha_hash(key, key_len, cx->ctx); /* hash long key data into hash */ - } - else /* otherwise store key data */ - memcpy(cx->key + cx->klen, key, key_len); - - cx->klen += key_len; /* update the key length count */ - return HMAC_OK; -} - -/* input the HMAC data (can be called multiple times) - */ -/* note that this call terminates the key input phase */ -void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]) -{ unsigned int i; - - if(cx->klen != HMAC_IN_DATA) /* if not yet in data phase */ - { - if(cx->klen > HASH_INPUT_SIZE) /* if key is being hashed */ - { /* complete the hash and */ - sha_end(cx->key, cx->ctx); /* store the result as the */ - cx->klen = HASH_OUTPUT_SIZE; /* key and set new length */ - } - - /* pad the key if necessary */ - memset(cx->key + cx->klen, 0, HASH_INPUT_SIZE - cx->klen); - - /* xor ipad into key value */ - for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) - ((uint_32t*)cx->key)[i] ^= 0x36363636; - - /* and start hash operation */ - sha_begin(cx->ctx); - sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); - - /* mark as now in data mode */ - cx->klen = HMAC_IN_DATA; - } - - /* hash the data (if any) */ - if(data_len) - sha_hash(data, data_len, cx->ctx); -} - -/* compute and output the MAC value */ -void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]) -{ unsigned char dig[HASH_OUTPUT_SIZE]; - unsigned int i; - - /* if no data has been entered perform a null data phase */ - if(cx->klen != HMAC_IN_DATA) - hmac_sha_data((const unsigned char*)0, 0, cx); - - sha_end(dig, cx->ctx); /* complete the inner hash */ - - /* set outer key value using opad and removing ipad */ - for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) - ((uint_32t*)cx->key)[i] ^= 0x36363636 ^ 0x5c5c5c5c; - - /* perform the outer hash operation */ - sha_begin(cx->ctx); - sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); - sha_hash(dig, HASH_OUTPUT_SIZE, cx->ctx); - sha_end(dig, cx->ctx); - - /* output the hash value */ - for(i = 0; i < mac_len; ++i) - mac[i] = dig[i]; -} - -/* 'do it all in one go' subroutine */ -void hmac_sha(const unsigned char key[], unsigned long key_len, - const unsigned char data[], unsigned long data_len, - unsigned char mac[], unsigned long mac_len) -{ hmac_ctx cx[1]; - - hmac_sha_begin(cx); - hmac_sha_key(key, key_len, cx); - hmac_sha_data(data, data_len, cx); - hmac_sha_end(mac, mac_len, cx); -} - -#if defined(__cplusplus) -} -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of HMAC, the FIPS standard keyed hash function +*/ + +#include "hmac.h" +#include "brg_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* initialise the HMAC context to zero */ +void hmac_sha_begin(hmac_ctx cx[1]) +{ + memset(cx, 0, sizeof(hmac_ctx)); +} + +/* input the HMAC key (can be called multiple times) */ +int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]) +{ + if(cx->klen == HMAC_IN_DATA) /* error if further key input */ + return HMAC_BAD_MODE; /* is attempted in data mode */ + + if(cx->klen + key_len > HASH_INPUT_SIZE) /* if the key has to be hashed */ + { + if(cx->klen <= HASH_INPUT_SIZE) /* if the hash has not yet been */ + { /* started, initialise it and */ + sha_begin(cx->ctx); /* hash stored key characters */ + sha_hash(cx->key, cx->klen, cx->ctx); + } + + sha_hash(key, key_len, cx->ctx); /* hash long key data into hash */ + } + else /* otherwise store key data */ + memcpy(cx->key + cx->klen, key, key_len); + + cx->klen += key_len; /* update the key length count */ + return HMAC_OK; +} + +/* input the HMAC data (can be called multiple times) - */ +/* note that this call terminates the key input phase */ +void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]) +{ unsigned int i; + + if(cx->klen != HMAC_IN_DATA) /* if not yet in data phase */ + { + if(cx->klen > HASH_INPUT_SIZE) /* if key is being hashed */ + { /* complete the hash and */ + sha_end(cx->key, cx->ctx); /* store the result as the */ + cx->klen = HASH_OUTPUT_SIZE; /* key and set new length */ + } + + /* pad the key if necessary */ + memset(cx->key + cx->klen, 0, HASH_INPUT_SIZE - cx->klen); + + /* xor ipad into key value */ + for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) + ((uint_32t*)cx->key)[i] ^= 0x36363636; + + /* and start hash operation */ + sha_begin(cx->ctx); + sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); + + /* mark as now in data mode */ + cx->klen = HMAC_IN_DATA; + } + + /* hash the data (if any) */ + if(data_len) + sha_hash(data, data_len, cx->ctx); +} + +/* compute and output the MAC value */ +void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]) +{ unsigned char dig[HASH_OUTPUT_SIZE]; + unsigned int i; + + /* if no data has been entered perform a null data phase */ + if(cx->klen != HMAC_IN_DATA) + hmac_sha_data((const unsigned char*)0, 0, cx); + + sha_end(dig, cx->ctx); /* complete the inner hash */ + + /* set outer key value using opad and removing ipad */ + for(i = 0; i < (HASH_INPUT_SIZE >> 2); ++i) + ((uint_32t*)cx->key)[i] ^= 0x36363636 ^ 0x5c5c5c5c; + + /* perform the outer hash operation */ + sha_begin(cx->ctx); + sha_hash(cx->key, HASH_INPUT_SIZE, cx->ctx); + sha_hash(dig, HASH_OUTPUT_SIZE, cx->ctx); + sha_end(dig, cx->ctx); + + /* output the hash value */ + for(i = 0; i < mac_len; ++i) + mac[i] = dig[i]; +} + +/* 'do it all in one go' subroutine */ +void hmac_sha(const unsigned char key[], unsigned long key_len, + const unsigned char data[], unsigned long data_len, + unsigned char mac[], unsigned long mac_len) +{ hmac_ctx cx[1]; + + hmac_sha_begin(cx); + hmac_sha_key(key, key_len, cx); + hmac_sha_data(data, data_len, cx); + hmac_sha_end(mac, mac_len, cx); +} + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/hmac.h b/libs/minizip/source/aes/hmac.h index 419cc15f..643037c9 100644 --- a/libs/minizip/source/aes/hmac.h +++ b/libs/minizip/source/aes/hmac.h @@ -1,103 +1,103 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 26/08/2003 - - This is an implementation of HMAC, the FIPS standard keyed hash function -*/ - -#ifndef _HMAC_H -#define _HMAC_H - -#include - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define USE_SHA1 - -#if !defined(USE_SHA1) && !defined(USE_SHA256) -#error define USE_SHA1 or USE_SHA256 to set the HMAC hash algorithm -#endif - -#ifdef USE_SHA1 - -#include "sha1.h" - -#define HASH_INPUT_SIZE SHA1_BLOCK_SIZE -#define HASH_OUTPUT_SIZE SHA1_DIGEST_SIZE -#define sha_ctx sha1_ctx -#define sha_begin sha1_begin -#define sha_hash sha1_hash -#define sha_end sha1_end - -#endif - -#ifdef USE_SHA256 - -#include "sha2.h" - -#define HASH_INPUT_SIZE SHA256_BLOCK_SIZE -#define HASH_OUTPUT_SIZE SHA256_DIGEST_SIZE -#define sha_ctx sha256_ctx -#define sha_begin sha256_begin -#define sha_hash sha256_hash -#define sha_end sha256_end - -#endif - -#define HMAC_OK 0 -#define HMAC_BAD_MODE -1 -#define HMAC_IN_DATA 0xffffffff - -typedef struct -{ unsigned char key[HASH_INPUT_SIZE]; - sha_ctx ctx[1]; - unsigned long klen; -} hmac_ctx; - -void hmac_sha_begin(hmac_ctx cx[1]); - -int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]); - -void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]); - -void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]); - -void hmac_sha(const unsigned char key[], unsigned long key_len, - const unsigned char data[], unsigned long data_len, - unsigned char mac[], unsigned long mac_len); - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of HMAC, the FIPS standard keyed hash function +*/ + +#ifndef _HMAC_H +#define _HMAC_H + +#include + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define USE_SHA1 + +#if !defined(USE_SHA1) && !defined(USE_SHA256) +#error define USE_SHA1 or USE_SHA256 to set the HMAC hash algorithm +#endif + +#ifdef USE_SHA1 + +#include "sha1.h" + +#define HASH_INPUT_SIZE SHA1_BLOCK_SIZE +#define HASH_OUTPUT_SIZE SHA1_DIGEST_SIZE +#define sha_ctx sha1_ctx +#define sha_begin sha1_begin +#define sha_hash sha1_hash +#define sha_end sha1_end + +#endif + +#ifdef USE_SHA256 + +#include "sha2.h" + +#define HASH_INPUT_SIZE SHA256_BLOCK_SIZE +#define HASH_OUTPUT_SIZE SHA256_DIGEST_SIZE +#define sha_ctx sha256_ctx +#define sha_begin sha256_begin +#define sha_hash sha256_hash +#define sha_end sha256_end + +#endif + +#define HMAC_OK 0 +#define HMAC_BAD_MODE -1 +#define HMAC_IN_DATA 0xffffffff + +typedef struct +{ unsigned char key[HASH_INPUT_SIZE]; + sha_ctx ctx[1]; + unsigned long klen; +} hmac_ctx; + +void hmac_sha_begin(hmac_ctx cx[1]); + +int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]); + +void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]); + +void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]); + +void hmac_sha(const unsigned char key[], unsigned long key_len, + const unsigned char data[], unsigned long data_len, + unsigned char mac[], unsigned long mac_len); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/prng.c b/libs/minizip/source/aes/prng.c index 14fc09d4..2f910907 100644 --- a/libs/minizip/source/aes/prng.c +++ b/libs/minizip/source/aes/prng.c @@ -1,155 +1,155 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 24/01/2003 - - This file implements a random data pool based on the use of an external - entropy function. It is based on the ideas advocated by Peter Gutmann in - his work on pseudo random sequence generators. It is not a 'paranoid' - random sequence generator and no attempt is made to protect the pool - from prying eyes either by memory locking or by techniques to obscure - its location in memory. -*/ - -#include -#include "prng.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* mix a random data pool using the SHA1 compression function (as */ -/* suggested by Peter Gutmann in his paper on random pools) */ - -static void prng_mix(unsigned char buf[]) -{ unsigned int i, len; - sha1_ctx ctx[1]; - - /*lint -e{663} unusual array to pointer conversion */ - for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE) - { - /* copy digest size pool block into SHA1 hash block */ - memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE) - - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE); - - /* copy data from pool into the SHA1 data buffer */ - len = PRNG_POOL_SIZE - i; - memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len)); - - if(len < SHA1_BLOCK_SIZE) - memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len); - - /* compress using the SHA1 compression function */ - sha1_compile(ctx); - - /* put digest size block back into the random pool */ - memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE); - } -} - -/* refresh the output buffer and update the random pool by adding */ -/* entropy and remixing */ - -static void update_pool(prng_ctx ctx[1]) -{ unsigned int i = 0; - - /* transfer random pool data to the output buffer */ - memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE); - - /* enter entropy data into the pool */ - while(i < PRNG_POOL_SIZE) - i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i); - - /* invert and xor the original pool data into the pool */ - for(i = 0; i < PRNG_POOL_SIZE; ++i) - ctx->rbuf[i] ^= ~ctx->obuf[i]; - - /* mix the pool and the output buffer */ - prng_mix(ctx->rbuf); - prng_mix(ctx->obuf); -} - -void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]) -{ int i; - - /* clear the buffers and the counter in the context */ - memset(ctx, 0, sizeof(prng_ctx)); - - /* set the pointer to the entropy collection function */ - ctx->entropy = fun; - - /* initialise the random data pool */ - update_pool(ctx); - - /* mix the pool a minimum number of times */ - for(i = 0; i < PRNG_MIN_MIX; ++i) - prng_mix(ctx->rbuf); - - /* update the pool to prime the pool output buffer */ - update_pool(ctx); -} - -/* provide random bytes from the random data pool */ - -void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]) -{ unsigned char *rp = data; - unsigned int len, pos = ctx->pos; - - while(data_len) - { - /* transfer 'data_len' bytes (or the number of bytes remaining */ - /* the pool output buffer if less) into the output */ - len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos); - memcpy(rp, ctx->obuf + pos, len); - rp += len; /* update ouput buffer position pointer */ - pos += len; /* update pool output buffer pointer */ - data_len -= len; /* update the remaining data count */ - - /* refresh the random pool if necessary */ - if(pos == PRNG_POOL_SIZE) - { - update_pool(ctx); pos = 0; - } - } - - ctx->pos = pos; -} - -void prng_end(prng_ctx ctx[1]) -{ - /* ensure the data in the context is destroyed */ - memset(ctx, 0, sizeof(prng_ctx)); -} - -#if defined(__cplusplus) -} -#endif - +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This file implements a random data pool based on the use of an external + entropy function. It is based on the ideas advocated by Peter Gutmann in + his work on pseudo random sequence generators. It is not a 'paranoid' + random sequence generator and no attempt is made to protect the pool + from prying eyes either by memory locking or by techniques to obscure + its location in memory. +*/ + +#include +#include "prng.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* mix a random data pool using the SHA1 compression function (as */ +/* suggested by Peter Gutmann in his paper on random pools) */ + +static void prng_mix(unsigned char buf[]) +{ unsigned int i, len; + sha1_ctx ctx[1]; + + /*lint -e{663} unusual array to pointer conversion */ + for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE) + { + /* copy digest size pool block into SHA1 hash block */ + memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE) + - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE); + + /* copy data from pool into the SHA1 data buffer */ + len = PRNG_POOL_SIZE - i; + memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len)); + + if(len < SHA1_BLOCK_SIZE) + memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len); + + /* compress using the SHA1 compression function */ + sha1_compile(ctx); + + /* put digest size block back into the random pool */ + memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE); + } +} + +/* refresh the output buffer and update the random pool by adding */ +/* entropy and remixing */ + +static void update_pool(prng_ctx ctx[1]) +{ unsigned int i = 0; + + /* transfer random pool data to the output buffer */ + memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE); + + /* enter entropy data into the pool */ + while(i < PRNG_POOL_SIZE) + i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i); + + /* invert and xor the original pool data into the pool */ + for(i = 0; i < PRNG_POOL_SIZE; ++i) + ctx->rbuf[i] ^= ~ctx->obuf[i]; + + /* mix the pool and the output buffer */ + prng_mix(ctx->rbuf); + prng_mix(ctx->obuf); +} + +void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]) +{ int i; + + /* clear the buffers and the counter in the context */ + memset(ctx, 0, sizeof(prng_ctx)); + + /* set the pointer to the entropy collection function */ + ctx->entropy = fun; + + /* initialise the random data pool */ + update_pool(ctx); + + /* mix the pool a minimum number of times */ + for(i = 0; i < PRNG_MIN_MIX; ++i) + prng_mix(ctx->rbuf); + + /* update the pool to prime the pool output buffer */ + update_pool(ctx); +} + +/* provide random bytes from the random data pool */ + +void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]) +{ unsigned char *rp = data; + unsigned int len, pos = ctx->pos; + + while(data_len) + { + /* transfer 'data_len' bytes (or the number of bytes remaining */ + /* the pool output buffer if less) into the output */ + len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos); + memcpy(rp, ctx->obuf + pos, len); + rp += len; /* update ouput buffer position pointer */ + pos += len; /* update pool output buffer pointer */ + data_len -= len; /* update the remaining data count */ + + /* refresh the random pool if necessary */ + if(pos == PRNG_POOL_SIZE) + { + update_pool(ctx); pos = 0; + } + } + + ctx->pos = pos; +} + +void prng_end(prng_ctx ctx[1]) +{ + /* ensure the data in the context is destroyed */ + memset(ctx, 0, sizeof(prng_ctx)); +} + +#if defined(__cplusplus) +} +#endif + diff --git a/libs/minizip/source/aes/prng.h b/libs/minizip/source/aes/prng.h index 9a774267..f934b519 100644 --- a/libs/minizip/source/aes/prng.h +++ b/libs/minizip/source/aes/prng.h @@ -1,82 +1,82 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 24/01/2003 - - This is the header file for an implementation of a random data pool based on - the use of an external entropy function (inspired by Peter Gutmann's work). -*/ - -#ifndef _PRNG_H -#define _PRNG_H - -#include "sha1.h" - -#define PRNG_POOL_LEN 256 /* minimum random pool size */ -#define PRNG_MIN_MIX 20 /* min initial pool mixing iterations */ - -/* ensure that pool length is a multiple of the SHA1 digest size */ - -#define PRNG_POOL_SIZE (SHA1_DIGEST_SIZE * (1 + (PRNG_POOL_LEN - 1) / SHA1_DIGEST_SIZE)) - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* A function for providing entropy is a parameter in the prng_init() */ -/* call. This function has the following form and returns a maximum */ -/* of 'len' bytes of pseudo random data in the buffer 'buf'. It can */ -/* return less than 'len' bytes but will be repeatedly called for more */ -/* data in this case. */ - -typedef int (*prng_entropy_fn)(unsigned char buf[], unsigned int len); - -typedef struct -{ unsigned char rbuf[PRNG_POOL_SIZE]; /* the random pool */ - unsigned char obuf[PRNG_POOL_SIZE]; /* pool output buffer */ - unsigned int pos; /* output buffer position */ - prng_entropy_fn entropy; /* entropy function pointer */ -} prng_ctx; - -/* initialise the random stream generator */ -void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]); - -/* obtain random bytes from the generator */ -void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]); - -/* close the random stream generator */ -void prng_end(prng_ctx ctx[1]); - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This is the header file for an implementation of a random data pool based on + the use of an external entropy function (inspired by Peter Gutmann's work). +*/ + +#ifndef _PRNG_H +#define _PRNG_H + +#include "sha1.h" + +#define PRNG_POOL_LEN 256 /* minimum random pool size */ +#define PRNG_MIN_MIX 20 /* min initial pool mixing iterations */ + +/* ensure that pool length is a multiple of the SHA1 digest size */ + +#define PRNG_POOL_SIZE (SHA1_DIGEST_SIZE * (1 + (PRNG_POOL_LEN - 1) / SHA1_DIGEST_SIZE)) + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* A function for providing entropy is a parameter in the prng_init() */ +/* call. This function has the following form and returns a maximum */ +/* of 'len' bytes of pseudo random data in the buffer 'buf'. It can */ +/* return less than 'len' bytes but will be repeatedly called for more */ +/* data in this case. */ + +typedef int (*prng_entropy_fn)(unsigned char buf[], unsigned int len); + +typedef struct +{ unsigned char rbuf[PRNG_POOL_SIZE]; /* the random pool */ + unsigned char obuf[PRNG_POOL_SIZE]; /* pool output buffer */ + unsigned int pos; /* output buffer position */ + prng_entropy_fn entropy; /* entropy function pointer */ +} prng_ctx; + +/* initialise the random stream generator */ +void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]); + +/* obtain random bytes from the generator */ +void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]); + +/* close the random stream generator */ +void prng_end(prng_ctx ctx[1]); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/pwd2key.c b/libs/minizip/source/aes/pwd2key.c index d3c6abbf..80a47603 100644 --- a/libs/minizip/source/aes/pwd2key.c +++ b/libs/minizip/source/aes/pwd2key.c @@ -1,193 +1,193 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 26/08/2003 - - This is an implementation of RFC2898, which specifies key derivation from - a password and a salt value. -*/ - -#include -#include "hmac.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -void derive_key(const unsigned char pwd[], /* the PASSWORD */ - unsigned int pwd_len, /* and its length */ - const unsigned char salt[], /* the SALT and its */ - unsigned int salt_len, /* length */ - unsigned int iter, /* the number of iterations */ - unsigned char key[], /* space for the output key */ - unsigned int key_len)/* and its required length */ -{ - unsigned int i, j, k, n_blk; - unsigned char uu[HASH_OUTPUT_SIZE], ux[HASH_OUTPUT_SIZE]; - hmac_ctx c1[1], c2[1], c3[1]; - - /* set HMAC context (c1) for password */ - hmac_sha_begin(c1); - hmac_sha_key(pwd, pwd_len, c1); - - /* set HMAC context (c2) for password and salt */ - memcpy(c2, c1, sizeof(hmac_ctx)); - hmac_sha_data(salt, salt_len, c2); - - /* find the number of SHA blocks in the key */ - n_blk = 1 + (key_len - 1) / HASH_OUTPUT_SIZE; - - for(i = 0; i < n_blk; ++i) /* for each block in key */ - { - /* ux[] holds the running xor value */ - memset(ux, 0, HASH_OUTPUT_SIZE); - - /* set HMAC context (c3) for password and salt */ - memcpy(c3, c2, sizeof(hmac_ctx)); - - /* enter additional data for 1st block into uu */ - uu[0] = (unsigned char)((i + 1) >> 24); - uu[1] = (unsigned char)((i + 1) >> 16); - uu[2] = (unsigned char)((i + 1) >> 8); - uu[3] = (unsigned char)(i + 1); - - /* this is the key mixing iteration */ - for(j = 0, k = 4; j < iter; ++j) - { - /* add previous round data to HMAC */ - hmac_sha_data(uu, k, c3); - - /* obtain HMAC for uu[] */ - hmac_sha_end(uu, HASH_OUTPUT_SIZE, c3); - - /* xor into the running xor block */ - for(k = 0; k < HASH_OUTPUT_SIZE; ++k) - ux[k] ^= uu[k]; - - /* set HMAC context (c3) for password */ - memcpy(c3, c1, sizeof(hmac_ctx)); - } - - /* compile key blocks into the key output */ - j = 0; k = i * HASH_OUTPUT_SIZE; - while(j < HASH_OUTPUT_SIZE && k < key_len) - key[k++] = ux[j++]; - } -} - -#ifdef TEST - -#include - -struct -{ unsigned int pwd_len; - unsigned int salt_len; - unsigned int it_count; - unsigned char *pwd; - unsigned char salt[32]; - unsigned char key[32]; -} tests[] = -{ - { 8, 4, 5, (unsigned char*)"password", - { - 0x12, 0x34, 0x56, 0x78 - }, - { - 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7, - 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5 - } - }, - { 8, 8, 5, (unsigned char*)"password", - { - 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 - }, - { - 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, - 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49 - } - }, - { 8, 21, 1, (unsigned char*)"password", - { - "ATHENA.MIT.EDUraeburn" - }, - { - 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, - 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15 - } - }, - { 8, 21, 2, (unsigned char*)"password", - { - "ATHENA.MIT.EDUraeburn" - }, - { - 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, - 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d - } - }, - { 8, 21, 1200, (unsigned char*)"password", - { - "ATHENA.MIT.EDUraeburn" - }, - { - 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, - 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b - } - } -}; - -int main() -{ unsigned int i, j, key_len = 256; - unsigned char key[256]; - - printf("\nTest of RFC2898 Password Based Key Derivation"); - for(i = 0; i < 5; ++i) - { - derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt, - tests[i].salt_len, tests[i].it_count, key, key_len); - - printf("\ntest %i: ", i + 1); - printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good"); - for(j = 0; j < key_len && j < 64; j += 4) - { - if(j % 16 == 0) - printf("\n"); - printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]); - } - printf(j < key_len ? " ... \n" : "\n"); - } - printf("\n"); - return 0; -} - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of RFC2898, which specifies key derivation from + a password and a salt value. +*/ + +#include +#include "hmac.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +void derive_key(const unsigned char pwd[], /* the PASSWORD */ + unsigned int pwd_len, /* and its length */ + const unsigned char salt[], /* the SALT and its */ + unsigned int salt_len, /* length */ + unsigned int iter, /* the number of iterations */ + unsigned char key[], /* space for the output key */ + unsigned int key_len)/* and its required length */ +{ + unsigned int i, j, k, n_blk; + unsigned char uu[HASH_OUTPUT_SIZE], ux[HASH_OUTPUT_SIZE]; + hmac_ctx c1[1], c2[1], c3[1]; + + /* set HMAC context (c1) for password */ + hmac_sha_begin(c1); + hmac_sha_key(pwd, pwd_len, c1); + + /* set HMAC context (c2) for password and salt */ + memcpy(c2, c1, sizeof(hmac_ctx)); + hmac_sha_data(salt, salt_len, c2); + + /* find the number of SHA blocks in the key */ + n_blk = 1 + (key_len - 1) / HASH_OUTPUT_SIZE; + + for(i = 0; i < n_blk; ++i) /* for each block in key */ + { + /* ux[] holds the running xor value */ + memset(ux, 0, HASH_OUTPUT_SIZE); + + /* set HMAC context (c3) for password and salt */ + memcpy(c3, c2, sizeof(hmac_ctx)); + + /* enter additional data for 1st block into uu */ + uu[0] = (unsigned char)((i + 1) >> 24); + uu[1] = (unsigned char)((i + 1) >> 16); + uu[2] = (unsigned char)((i + 1) >> 8); + uu[3] = (unsigned char)(i + 1); + + /* this is the key mixing iteration */ + for(j = 0, k = 4; j < iter; ++j) + { + /* add previous round data to HMAC */ + hmac_sha_data(uu, k, c3); + + /* obtain HMAC for uu[] */ + hmac_sha_end(uu, HASH_OUTPUT_SIZE, c3); + + /* xor into the running xor block */ + for(k = 0; k < HASH_OUTPUT_SIZE; ++k) + ux[k] ^= uu[k]; + + /* set HMAC context (c3) for password */ + memcpy(c3, c1, sizeof(hmac_ctx)); + } + + /* compile key blocks into the key output */ + j = 0; k = i * HASH_OUTPUT_SIZE; + while(j < HASH_OUTPUT_SIZE && k < key_len) + key[k++] = ux[j++]; + } +} + +#ifdef TEST + +#include + +struct +{ unsigned int pwd_len; + unsigned int salt_len; + unsigned int it_count; + unsigned char *pwd; + unsigned char salt[32]; + unsigned char key[32]; +} tests[] = +{ + { 8, 4, 5, (unsigned char*)"password", + { + 0x12, 0x34, 0x56, 0x78 + }, + { + 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7, + 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5 + } + }, + { 8, 8, 5, (unsigned char*)"password", + { + 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 + }, + { + 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, + 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49 + } + }, + { 8, 21, 1, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, + 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15 + } + }, + { 8, 21, 2, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, + 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d + } + }, + { 8, 21, 1200, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, + 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b + } + } +}; + +int main() +{ unsigned int i, j, key_len = 256; + unsigned char key[256]; + + printf("\nTest of RFC2898 Password Based Key Derivation"); + for(i = 0; i < 5; ++i) + { + derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt, + tests[i].salt_len, tests[i].it_count, key, key_len); + + printf("\ntest %i: ", i + 1); + printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good"); + for(j = 0; j < key_len && j < 64; j += 4) + { + if(j % 16 == 0) + printf("\n"); + printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]); + } + printf(j < key_len ? " ... \n" : "\n"); + } + printf("\n"); + return 0; +} + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/pwd2key.h b/libs/minizip/source/aes/pwd2key.h index d95a5b9f..99c1ecc1 100644 --- a/libs/minizip/source/aes/pwd2key.h +++ b/libs/minizip/source/aes/pwd2key.h @@ -1,57 +1,57 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 26/08/2003 - - This is an implementation of RFC2898, which specifies key derivation from - a password and a salt value. -*/ - -#ifndef PWD2KEY_H -#define PWD2KEY_H - -#if defined(__cplusplus) -extern "C" -{ -#endif - -void derive_key( - const unsigned char pwd[], /* the PASSWORD, and */ - unsigned int pwd_len, /* its length */ - const unsigned char salt[], /* the SALT and its */ - unsigned int salt_len, /* length */ - unsigned int iter, /* the number of iterations */ - unsigned char key[], /* space for the output key */ - unsigned int key_len); /* and its required length */ - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of RFC2898, which specifies key derivation from + a password and a salt value. +*/ + +#ifndef PWD2KEY_H +#define PWD2KEY_H + +#if defined(__cplusplus) +extern "C" +{ +#endif + +void derive_key( + const unsigned char pwd[], /* the PASSWORD, and */ + unsigned int pwd_len, /* its length */ + const unsigned char salt[], /* the SALT and its */ + unsigned int salt_len, /* length */ + unsigned int iter, /* the number of iterations */ + unsigned char key[], /* space for the output key */ + unsigned int key_len); /* and its required length */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/aes/sha1.c b/libs/minizip/source/aes/sha1.c index bb547428..0fbf05e6 100644 --- a/libs/minizip/source/aes/sha1.c +++ b/libs/minizip/source/aes/sha1.c @@ -1,258 +1,258 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 - - This is a byte oriented version of SHA1 that operates on arrays of bytes - stored in memory. -*/ - -#include /* for memcpy() etc. */ - -#include "sha1.h" -#include "brg_endian.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) -#pragma intrinsic(memcpy) -#endif - -#if 0 && defined(_MSC_VER) -#define rotl32 _lrotl -#define rotr32 _lrotr -#else -#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) -#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) -#endif - -#if !defined(bswap_32) -#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) -#endif - -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) -#define SWAP_BYTES -#else -#undef SWAP_BYTES -#endif - -#if defined(SWAP_BYTES) -#define bsw_32(p,n) \ - { int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); } -#else -#define bsw_32(p,n) -#endif - -#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) - -#if 0 - -#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -#else /* Discovered by Rich Schroeppel and Colin Plumb */ - -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) - -#endif - -/* Compile 64 bytes of hash data into SHA1 context. Note */ -/* that this routine assumes that the byte order in the */ -/* ctx->wbuf[] at this point is in such an order that low */ -/* address bytes in the ORIGINAL byte stream will go in */ -/* this buffer to the high end of 32-bit words on BOTH big */ -/* and little endian systems */ - -#ifdef ARRAY -#define q(v,n) v[n] -#else -#define q(v,n) v##n -#endif - -#define one_cycle(v,a,b,c,d,e,f,k,h) \ - q(v,e) += rotr32(q(v,a),27) + \ - f(q(v,b),q(v,c),q(v,d)) + k + h; \ - q(v,b) = rotr32(q(v,b), 2) - -#define five_cycle(v,f,k,i) \ - one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \ - one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \ - one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \ - one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \ - one_cycle(v, 1,2,3,4,0, f,k,hf(i+4)) - -VOID_RETURN sha1_compile(sha1_ctx ctx[1]) -{ uint_32t *w = ctx->wbuf; - -#ifdef ARRAY - uint_32t v[5]; - memcpy(v, ctx->hash, 5 * sizeof(uint_32t)); -#else - uint_32t v0, v1, v2, v3, v4; - v0 = ctx->hash[0]; v1 = ctx->hash[1]; - v2 = ctx->hash[2]; v3 = ctx->hash[3]; - v4 = ctx->hash[4]; -#endif - -#define hf(i) w[i] - - five_cycle(v, ch, 0x5a827999, 0); - five_cycle(v, ch, 0x5a827999, 5); - five_cycle(v, ch, 0x5a827999, 10); - one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \ - -#undef hf -#define hf(i) (w[(i) & 15] = rotl32( \ - w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \ - ^ w[((i) + 2) & 15] ^ w[(i) & 15], 1)) - - one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16)); - one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17)); - one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18)); - one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19)); - - five_cycle(v, parity, 0x6ed9eba1, 20); - five_cycle(v, parity, 0x6ed9eba1, 25); - five_cycle(v, parity, 0x6ed9eba1, 30); - five_cycle(v, parity, 0x6ed9eba1, 35); - - five_cycle(v, maj, 0x8f1bbcdc, 40); - five_cycle(v, maj, 0x8f1bbcdc, 45); - five_cycle(v, maj, 0x8f1bbcdc, 50); - five_cycle(v, maj, 0x8f1bbcdc, 55); - - five_cycle(v, parity, 0xca62c1d6, 60); - five_cycle(v, parity, 0xca62c1d6, 65); - five_cycle(v, parity, 0xca62c1d6, 70); - five_cycle(v, parity, 0xca62c1d6, 75); - -#ifdef ARRAY - ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; - ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; - ctx->hash[4] += v[4]; -#else - ctx->hash[0] += v0; ctx->hash[1] += v1; - ctx->hash[2] += v2; ctx->hash[3] += v3; - ctx->hash[4] += v4; -#endif -} - -VOID_RETURN sha1_begin(sha1_ctx ctx[1]) -{ - ctx->count[0] = ctx->count[1] = 0; - ctx->hash[0] = 0x67452301; - ctx->hash[1] = 0xefcdab89; - ctx->hash[2] = 0x98badcfe; - ctx->hash[3] = 0x10325476; - ctx->hash[4] = 0xc3d2e1f0; -} - -/* SHA1 hash data in an array of bytes into hash buffer and */ -/* call the hash_compile function as required. */ - -VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]) -{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA1_MASK), - space = SHA1_BLOCK_SIZE - pos; - const unsigned char *sp = data; - - if((ctx->count[0] += len) < len) - ++(ctx->count[1]); - - while(len >= space) /* tranfer whole blocks if possible */ - { - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); - sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0; - bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2); - sha1_compile(ctx); - } - - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); -} - -/* SHA1 final padding and digest calculation */ - -VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]) -{ uint_32t i = (uint_32t)(ctx->count[0] & SHA1_MASK); - - /* put bytes in the buffer in an order in which references to */ - /* 32-bit words will put bytes with lower addresses into the */ - /* top of 32 bit words on BOTH big and little endian machines */ - bsw_32(ctx->wbuf, (i + 3) >> 2); - - /* we now need to mask valid bytes and add the padding which is */ - /* a single 1 bit and as many zero bits as necessary. Note that */ - /* we can always add the first padding byte here because the */ - /* buffer always has at least one empty slot */ - ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3); - ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3); - - /* we need 9 or more empty positions, one for the padding byte */ - /* (above) and eight for the length count. If there is not */ - /* enough space, pad and empty the buffer */ - if(i > SHA1_BLOCK_SIZE - 9) - { - if(i < 60) ctx->wbuf[15] = 0; - sha1_compile(ctx); - i = 0; - } - else /* compute a word index for the empty buffer positions */ - i = (i >> 2) + 1; - - while(i < 14) /* and zero pad all but last two positions */ - ctx->wbuf[i++] = 0; - - /* the following 32-bit length fields are assembled in the */ - /* wrong byte order on little endian machines but this is */ - /* corrected later since they are only ever used as 32-bit */ - /* word values. */ - ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); - ctx->wbuf[15] = ctx->count[0] << 3; - sha1_compile(ctx); - - /* extract the hash value as bytes in case the hash buffer is */ - /* misaligned for 32-bit words */ - for(i = 0; i < SHA1_DIGEST_SIZE; ++i) - hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); -} - -VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len) -{ sha1_ctx cx[1]; - - sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx); -} - -#if defined(__cplusplus) -} -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 01/08/2005 + + This is a byte oriented version of SHA1 that operates on arrays of bytes + stored in memory. +*/ + +#include /* for memcpy() etc. */ + +#include "sha1.h" +#include "brg_endian.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) +#pragma intrinsic(memcpy) +#endif + +#if 0 && defined(_MSC_VER) +#define rotl32 _lrotl +#define rotr32 _lrotr +#else +#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) +#endif + +#if !defined(bswap_32) +#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) +#endif + +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) +#define SWAP_BYTES +#else +#undef SWAP_BYTES +#endif + +#if defined(SWAP_BYTES) +#define bsw_32(p,n) \ + { int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); } +#else +#define bsw_32(p,n) +#endif + +#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) + +#if 0 + +#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* Discovered by Rich Schroeppel and Colin Plumb */ + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +#endif + +/* Compile 64 bytes of hash data into SHA1 context. Note */ +/* that this routine assumes that the byte order in the */ +/* ctx->wbuf[] at this point is in such an order that low */ +/* address bytes in the ORIGINAL byte stream will go in */ +/* this buffer to the high end of 32-bit words on BOTH big */ +/* and little endian systems */ + +#ifdef ARRAY +#define q(v,n) v[n] +#else +#define q(v,n) v##n +#endif + +#define one_cycle(v,a,b,c,d,e,f,k,h) \ + q(v,e) += rotr32(q(v,a),27) + \ + f(q(v,b),q(v,c),q(v,d)) + k + h; \ + q(v,b) = rotr32(q(v,b), 2) + +#define five_cycle(v,f,k,i) \ + one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \ + one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \ + one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \ + one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \ + one_cycle(v, 1,2,3,4,0, f,k,hf(i+4)) + +VOID_RETURN sha1_compile(sha1_ctx ctx[1]) +{ uint_32t *w = ctx->wbuf; + +#ifdef ARRAY + uint_32t v[5]; + memcpy(v, ctx->hash, 5 * sizeof(uint_32t)); +#else + uint_32t v0, v1, v2, v3, v4; + v0 = ctx->hash[0]; v1 = ctx->hash[1]; + v2 = ctx->hash[2]; v3 = ctx->hash[3]; + v4 = ctx->hash[4]; +#endif + +#define hf(i) w[i] + + five_cycle(v, ch, 0x5a827999, 0); + five_cycle(v, ch, 0x5a827999, 5); + five_cycle(v, ch, 0x5a827999, 10); + one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \ + +#undef hf +#define hf(i) (w[(i) & 15] = rotl32( \ + w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \ + ^ w[((i) + 2) & 15] ^ w[(i) & 15], 1)) + + one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16)); + one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17)); + one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18)); + one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19)); + + five_cycle(v, parity, 0x6ed9eba1, 20); + five_cycle(v, parity, 0x6ed9eba1, 25); + five_cycle(v, parity, 0x6ed9eba1, 30); + five_cycle(v, parity, 0x6ed9eba1, 35); + + five_cycle(v, maj, 0x8f1bbcdc, 40); + five_cycle(v, maj, 0x8f1bbcdc, 45); + five_cycle(v, maj, 0x8f1bbcdc, 50); + five_cycle(v, maj, 0x8f1bbcdc, 55); + + five_cycle(v, parity, 0xca62c1d6, 60); + five_cycle(v, parity, 0xca62c1d6, 65); + five_cycle(v, parity, 0xca62c1d6, 70); + five_cycle(v, parity, 0xca62c1d6, 75); + +#ifdef ARRAY + ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; + ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; + ctx->hash[4] += v[4]; +#else + ctx->hash[0] += v0; ctx->hash[1] += v1; + ctx->hash[2] += v2; ctx->hash[3] += v3; + ctx->hash[4] += v4; +#endif +} + +VOID_RETURN sha1_begin(sha1_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; +} + +/* SHA1 hash data in an array of bytes into hash buffer and */ +/* call the hash_compile function as required. */ + +VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]) +{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA1_MASK), + space = SHA1_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((ctx->count[0] += len) < len) + ++(ctx->count[1]); + + while(len >= space) /* tranfer whole blocks if possible */ + { + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); + sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0; + bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2); + sha1_compile(ctx); + } + + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); +} + +/* SHA1 final padding and digest calculation */ + +VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]) +{ uint_32t i = (uint_32t)(ctx->count[0] & SHA1_MASK); + + /* put bytes in the buffer in an order in which references to */ + /* 32-bit words will put bytes with lower addresses into the */ + /* top of 32 bit words on BOTH big and little endian machines */ + bsw_32(ctx->wbuf, (i + 3) >> 2); + + /* we now need to mask valid bytes and add the padding which is */ + /* a single 1 bit and as many zero bits as necessary. Note that */ + /* we can always add the first padding byte here because the */ + /* buffer always has at least one empty slot */ + ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3); + ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3); + + /* we need 9 or more empty positions, one for the padding byte */ + /* (above) and eight for the length count. If there is not */ + /* enough space, pad and empty the buffer */ + if(i > SHA1_BLOCK_SIZE - 9) + { + if(i < 60) ctx->wbuf[15] = 0; + sha1_compile(ctx); + i = 0; + } + else /* compute a word index for the empty buffer positions */ + i = (i >> 2) + 1; + + while(i < 14) /* and zero pad all but last two positions */ + ctx->wbuf[i++] = 0; + + /* the following 32-bit length fields are assembled in the */ + /* wrong byte order on little endian machines but this is */ + /* corrected later since they are only ever used as 32-bit */ + /* word values. */ + ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); + ctx->wbuf[15] = ctx->count[0] << 3; + sha1_compile(ctx); + + /* extract the hash value as bytes in case the hash buffer is */ + /* misaligned for 32-bit words */ + for(i = 0; i < SHA1_DIGEST_SIZE; ++i) + hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); +} + +VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha1_ctx cx[1]; + + sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx); +} + +#if defined(__cplusplus) +} +#endif diff --git a/libs/minizip/source/aes/sha1.h b/libs/minizip/source/aes/sha1.h index 65ee6d39..bace6afe 100644 --- a/libs/minizip/source/aes/sha1.h +++ b/libs/minizip/source/aes/sha1.h @@ -1,73 +1,73 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 -*/ - -#ifndef _SHA1_H -#define _SHA1_H - -#include -#include "brg_types.h" - -#define SHA1_BLOCK_SIZE 64 -#define SHA1_DIGEST_SIZE 20 - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* type to hold the SHA256 context */ - -typedef struct -{ uint_32t count[2]; - uint_32t hash[5]; - uint_32t wbuf[16]; -} sha1_ctx; - -/* Note that these prototypes are the same for both bit and */ -/* byte oriented implementations. However the length fields */ -/* are in bytes or bits as appropriate for the version used */ -/* and bit sequences are input as arrays of bytes in which */ -/* bit sequences run from the most to the least significant */ -/* end of each byte */ - -VOID_RETURN sha1_compile(sha1_ctx ctx[1]); - -VOID_RETURN sha1_begin(sha1_ctx ctx[1]); -VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]); -VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]); -VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len); - -#if defined(__cplusplus) -} -#endif - -#endif +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 01/08/2005 +*/ + +#ifndef _SHA1_H +#define _SHA1_H + +#include +#include "brg_types.h" + +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* type to hold the SHA256 context */ + +typedef struct +{ uint_32t count[2]; + uint_32t hash[5]; + uint_32t wbuf[16]; +} sha1_ctx; + +/* Note that these prototypes are the same for both bit and */ +/* byte oriented implementations. However the length fields */ +/* are in bytes or bits as appropriate for the version used */ +/* and bit sequences are input as arrays of bytes in which */ +/* bit sequences run from the most to the least significant */ +/* end of each byte */ + +VOID_RETURN sha1_compile(sha1_ctx ctx[1]); + +VOID_RETURN sha1_begin(sha1_ctx ctx[1]); +VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]); +VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]); +VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/libs/minizip/source/ioapi.c b/libs/minizip/source/ioapi.c index 4b2bead2..3679bb02 100644 --- a/libs/minizip/source/ioapi.c +++ b/libs/minizip/source/ioapi.c @@ -1,369 +1,369 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#include -#include - -#include "ioapi.h" - -#if defined(_WIN32) -# define snprintf _snprintf -#endif - -#ifdef __APPLE__ -/* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */ -# define FOPEN_FUNC(filename, mode) fopen(filename, mode) -# define FTELLO_FUNC(stream) ftello(stream) -# define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) -#else -# define FOPEN_FUNC(filename, mode) fopen64(filename, mode) -# define FTELLO_FUNC(stream) ftello64(stream) -# define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) -#endif - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ -#ifndef SEEK_CUR -# define SEEK_CUR 1 -#endif -#ifndef SEEK_END -# define SEEK_END 2 -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 -#endif - -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) -{ - if (pfilefunc->zfile_func64.zopen64_file != NULL) - return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); - return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); -} - -voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)) -{ - if (pfilefunc->zfile_func64.zopendisk64_file != NULL) - return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); - return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); -} - -long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) -{ - uLong offsetTruncated; - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); - offsetTruncated = (uLong)offset; - if (offsetTruncated != offset) - return -1; - return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); -} - -ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) -{ - uLong tell_uLong; - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); - tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); - if ((tell_uLong) == 0xffffffff) - return (ZPOS64_T)-1; - return tell_uLong; -} - -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) -{ - p_filefunc64_32->zfile_func64.zopen64_file = NULL; - p_filefunc64_32->zfile_func64.zopendisk64_file = NULL; - p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; - p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; - p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; - p_filefunc64_32->zfile_func64.ztell64_file = NULL; - p_filefunc64_32->zfile_func64.zseek64_file = NULL; - p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; - p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; - p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; -} - -static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); -static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); -static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); -static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); -static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); - -typedef struct -{ - FILE *file; - int filenameLength; - void *filename; -} FILE_IOPOSIX; - -static voidpf file_build_ioposix(FILE *file, const char *filename) -{ - FILE_IOPOSIX *ioposix = NULL; - if (file == NULL) - return NULL; - ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX)); - ioposix->file = file; - ioposix->filenameLength = strlen(filename) + 1; - ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char)); - strncpy(ioposix->filename, filename, ioposix->filenameLength); - return (voidpf)ioposix; -} - -static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename != NULL) && (mode_fopen != NULL)) - { - file = fopen(filename, mode_fopen); - return file_build_ioposix(file, filename); - } - return file; -} - -static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename != NULL) && (mode_fopen != NULL)) - { - file = FOPEN_FUNC((const char*)filename, mode_fopen); - return file_build_ioposix(file, (const char*)filename); - } - return file; -} - -static voidpf ZCALLBACK fopendisk64_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) -{ - FILE_IOPOSIX *ioposix = NULL; - char *diskFilename = NULL; - voidpf ret = NULL; - int i = 0; - - if (stream == NULL) - return NULL; - ioposix = (FILE_IOPOSIX*)stream; - diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); - strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); - for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) - { - if (diskFilename[i] != '.') - continue; - snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); - break; - } - if (i >= 0) - ret = fopen64_file_func(opaque, diskFilename, mode); - free(diskFilename); - return ret; -} - -static voidpf ZCALLBACK fopendisk_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) -{ - FILE_IOPOSIX *ioposix = NULL; - char *diskFilename = NULL; - voidpf ret = NULL; - int i = 0; - - if (stream == NULL) - return NULL; - ioposix = (FILE_IOPOSIX*)stream; - diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); - strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); - for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) - { - if (diskFilename[i] != '.') - continue; - snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); - break; - } - if (i >= 0) - ret = fopen_file_func(opaque, diskFilename, mode); - free(diskFilename); - return ret; -} - -static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) -{ - FILE_IOPOSIX *ioposix = NULL; - uLong ret; - if (stream == NULL) - return -1; - ioposix = (FILE_IOPOSIX*)stream; - ret = (uLong)fread(buf, 1, (size_t)size, ioposix->file); - return ret; -} - -static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) -{ - FILE_IOPOSIX *ioposix = NULL; - uLong ret; - if (stream == NULL) - return -1; - ioposix = (FILE_IOPOSIX*)stream; - ret = (uLong)fwrite(buf, 1, (size_t)size, ioposix->file); - return ret; -} - -static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) -{ - FILE_IOPOSIX *ioposix = NULL; - long ret = -1; - if (stream == NULL) - return ret; - ioposix = (FILE_IOPOSIX*)stream; - ret = ftell(ioposix->file); - return ret; -} - -static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) -{ - FILE_IOPOSIX *ioposix = NULL; - ZPOS64_T ret = -1; - if (stream == NULL) - return ret; - ioposix = (FILE_IOPOSIX*)stream; - ret = FTELLO_FUNC(ioposix->file); - return ret; -} - -static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) -{ - FILE_IOPOSIX *ioposix = NULL; - int fseek_origin = 0; - long ret = 0; - - if (stream == NULL) - return -1; - ioposix = (FILE_IOPOSIX*)stream; - - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR: - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END: - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET: - fseek_origin = SEEK_SET; - break; - default: - return -1; - } - if (fseek(ioposix->file, offset, fseek_origin) != 0) - ret = -1; - return ret; -} - -static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) -{ - FILE_IOPOSIX *ioposix = NULL; - int fseek_origin = 0; - long ret = 0; - - if (stream == NULL) - return -1; - ioposix = (FILE_IOPOSIX*)stream; - - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR: - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END: - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET: - fseek_origin = SEEK_SET; - break; - default: - return -1; - } - - if(FSEEKO_FUNC(ioposix->file, offset, fseek_origin) != 0) - ret = -1; - - return ret; -} - - -static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) -{ - FILE_IOPOSIX *ioposix = NULL; - int ret = -1; - if (stream == NULL) - return ret; - ioposix = (FILE_IOPOSIX*)stream; - if (ioposix->filename != NULL) - free(ioposix->filename); - ret = fclose(ioposix->file); - free(ioposix); - return ret; -} - -static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) -{ - FILE_IOPOSIX *ioposix = NULL; - int ret = -1; - if (stream == NULL) - return ret; - ioposix = (FILE_IOPOSIX*)stream; - ret = ferror(ioposix->file); - return ret; -} - -void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = fopen_file_func; - pzlib_filefunc_def->zopendisk_file = fopendisk_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell_file = ftell_file_func; - pzlib_filefunc_def->zseek_file = fseek_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} - -void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = fopen64_file_func; - pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell64_file = ftell64_file_func; - pzlib_filefunc_def->zseek64_file = fseek64_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include +#include + +#include "ioapi.h" + +#if defined(_WIN32) +# define snprintf _snprintf +#endif + +#ifdef __APPLE__ +/* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */ +# define FOPEN_FUNC(filename, mode) fopen(filename, mode) +# define FTELLO_FUNC(stream) ftello(stream) +# define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +# define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +# define FTELLO_FUNC(stream) ftello64(stream) +# define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ +#ifndef SEEK_CUR +# define SEEK_CUR 1 +#endif +#ifndef SEEK_END +# define SEEK_END 2 +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); +} + +voidpf call_zopendisk64 OF((const zlib_filefunc64_32_def* pfilefunc, voidpf filestream, int number_disk, int mode)) +{ + if (pfilefunc->zfile_func64.zopendisk64_file != NULL) + return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); + return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque,filestream,number_disk,mode); +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + uLong offsetTruncated; + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + uLong tell_uLong; + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == 0xffffffff) + return (ZPOS64_T)-1; + return tell_uLong; +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zfile_func64.zopendisk64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + FILE *file; + int filenameLength; + void *filename; +} FILE_IOPOSIX; + +static voidpf file_build_ioposix(FILE *file, const char *filename) +{ + FILE_IOPOSIX *ioposix = NULL; + if (file == NULL) + return NULL; + ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX)); + ioposix->file = file; + ioposix->filenameLength = strlen(filename) + 1; + ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char)); + strncpy(ioposix->filename, filename, ioposix->filenameLength); + return (voidpf)ioposix; +} + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename != NULL) && (mode_fopen != NULL)) + { + file = fopen(filename, mode_fopen); + return file_build_ioposix(file, filename); + } + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename != NULL) && (mode_fopen != NULL)) + { + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file_build_ioposix(file, (const char*)filename); + } + return file; +} + +static voidpf ZCALLBACK fopendisk64_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) +{ + FILE_IOPOSIX *ioposix = NULL; + char *diskFilename = NULL; + voidpf ret = NULL; + int i = 0; + + if (stream == NULL) + return NULL; + ioposix = (FILE_IOPOSIX*)stream; + diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); + strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); + for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) + { + if (diskFilename[i] != '.') + continue; + snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); + break; + } + if (i >= 0) + ret = fopen64_file_func(opaque, diskFilename, mode); + free(diskFilename); + return ret; +} + +static voidpf ZCALLBACK fopendisk_file_func (voidpf opaque, voidpf stream, int number_disk, int mode) +{ + FILE_IOPOSIX *ioposix = NULL; + char *diskFilename = NULL; + voidpf ret = NULL; + int i = 0; + + if (stream == NULL) + return NULL; + ioposix = (FILE_IOPOSIX*)stream; + diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char)); + strncpy(diskFilename, ioposix->filename, ioposix->filenameLength); + for (i = ioposix->filenameLength - 1; i >= 0; i -= 1) + { + if (diskFilename[i] != '.') + continue; + snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02d", number_disk + 1); + break; + } + if (i >= 0) + ret = fopen_file_func(opaque, diskFilename, mode); + free(diskFilename); + return ret; +} + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + FILE_IOPOSIX *ioposix = NULL; + uLong ret; + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + ret = (uLong)fread(buf, 1, (size_t)size, ioposix->file); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + FILE_IOPOSIX *ioposix = NULL; + uLong ret; + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + ret = (uLong)fwrite(buf, 1, (size_t)size, ioposix->file); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX *ioposix = NULL; + long ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = ftell(ioposix->file); + return ret; +} + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX *ioposix = NULL; + ZPOS64_T ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = FTELLO_FUNC(ioposix->file); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + FILE_IOPOSIX *ioposix = NULL; + int fseek_origin = 0; + long ret = 0; + + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR: + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END: + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET: + fseek_origin = SEEK_SET; + break; + default: + return -1; + } + if (fseek(ioposix->file, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + FILE_IOPOSIX *ioposix = NULL; + int fseek_origin = 0; + long ret = 0; + + if (stream == NULL) + return -1; + ioposix = (FILE_IOPOSIX*)stream; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR: + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END: + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET: + fseek_origin = SEEK_SET; + break; + default: + return -1; + } + + if(FSEEKO_FUNC(ioposix->file, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX *ioposix = NULL; + int ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + if (ioposix->filename != NULL) + free(ioposix->filename); + ret = fclose(ioposix->file); + free(ioposix); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + FILE_IOPOSIX *ioposix = NULL; + int ret = -1; + if (stream == NULL) + return ret; + ioposix = (FILE_IOPOSIX*)stream; + ret = ferror(ioposix->file); + return ret; +} + +void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zopendisk_file = fopendisk_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/libs/minizip/source/ioapi_buf.c b/libs/minizip/source/ioapi_buf.c index 521a6d9d..e960067a 100644 --- a/libs/minizip/source/ioapi_buf.c +++ b/libs/minizip/source/ioapi_buf.c @@ -1,514 +1,514 @@ -/* ioapi_buf.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - This version of ioapi is designed to buffer IO. - - Copyright (C) 1998-2003 Gilles Vollant - (C) 2012-2014 Nathan Moinvaziri - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - - -#include -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" - -#include "ioapi_buf.h" - -#if defined(_WIN32) -# include -# define PRINTF _cprintf -# define VPRINTF _vcprintf -#else -# define PRINTF printf -# define VPRINTF vprintf -#endif - -//#define IOBUF_VERBOSE - -#ifdef __GNUC__ -#ifndef max -#define max(x,y) ({ \ -const typeof(x) _x = (x); \ -const typeof(y) _y = (y); \ -(void) (&_x == &_y); \ -_x > _y ? _x : _y; }) -#endif /* __GNUC__ */ - -#ifndef min -#define min(x,y) ({ \ -const typeof(x) _x = (x); \ -const typeof(y) _y = (y); \ -(void) (&_x == &_y); \ -_x < _y ? _x : _y; }) -#endif -#endif - -typedef struct ourstream_s { - char readBuffer[IOBUF_BUFFERSIZE]; - uInt readBufferLength; - uInt readBufferPos; - uInt readBufferHits; - uInt readBufferMisses; - char writeBuffer[IOBUF_BUFFERSIZE]; - uInt writeBufferLength; - uInt writeBufferPos; - uInt writeBufferHits; - uInt writeBufferMisses; - ZPOS64_T position; - voidpf stream; -} ourstream_t; - -#if defined(IOBUF_VERBOSE) -# define print_buf(o,s,f,...) print_buf_internal(o,s,f,__VA_ARGS__); -#else -# define print_buf(o,s,f,...) -#endif - -void print_buf_internal(voidpf opaque, voidpf stream, char *format, ...) -{ - ourstream_t *streamio = (ourstream_t *)stream; - va_list arglist; - PRINTF("Buf stream %p - ", streamio); - va_start(arglist, format); - VPRINTF(format, arglist); - va_end(arglist); -} - -voidpf fopen_buf_internal_func (opaque, stream, number_disk, mode) - voidpf opaque; - voidpf stream; - int number_disk; - int mode; -{ - ourstream_t *streamio = NULL; - if (stream == NULL) - return NULL; - streamio = (ourstream_t *)malloc(sizeof(ourstream_t)); - if (streamio == NULL) - return NULL; - memset(streamio, 0, sizeof(ourstream_t)); - streamio->stream = stream; - print_buf(opaque, streamio, "open [num %d mode %d]\n", number_disk, mode); - return streamio; -} - -voidpf ZCALLBACK fopen_buf_func (opaque, filename, mode) - voidpf opaque; - const char* filename; - int mode; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - voidpf stream = bufio->filefunc.zopen_file(bufio->filefunc.opaque, filename, mode); - return fopen_buf_internal_func(opaque, stream, 0, mode); -} - -voidpf ZCALLBACK fopen64_buf_func (opaque, filename, mode) - voidpf opaque; - const char* filename; - int mode; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - voidpf stream = bufio->filefunc64.zopen64_file(bufio->filefunc64.opaque, filename, mode); - return fopen_buf_internal_func(opaque, stream, 0, mode); -} - -voidpf ZCALLBACK fopendisk_buf_func (opaque, stream_cd, number_disk, mode) - voidpf opaque; - voidpf stream_cd; - int number_disk; - int mode; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream_cd; - voidpf *stream = bufio->filefunc.zopendisk_file(bufio->filefunc.opaque, streamio->stream, number_disk, mode); - return fopen_buf_internal_func(opaque, stream, number_disk, mode); -} - -voidpf ZCALLBACK fopendisk64_buf_func (opaque, stream_cd, number_disk, mode) - voidpf opaque; - voidpf stream_cd; - int number_disk; - int mode; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream_cd; - voidpf stream = bufio->filefunc64.zopendisk64_file(bufio->filefunc64.opaque, streamio->stream, number_disk, mode); - return fopen_buf_internal_func(opaque, stream, number_disk, mode); -} - -long fflush_buf OF((voidpf opaque, voidpf stream)); -long fflush_buf (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - uInt totalBytesWritten = 0; - uInt bytesToWrite = streamio->writeBufferLength; - uInt bytesLeftToWrite = streamio->writeBufferLength; - int bytesWritten = 0; - - while (bytesLeftToWrite > 0) - { - if (bufio->filefunc64.zwrite_file != NULL) - bytesWritten = bufio->filefunc64.zwrite_file(bufio->filefunc64.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); - else - bytesWritten = bufio->filefunc.zwrite_file(bufio->filefunc.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); - - streamio->writeBufferMisses += 1; - - print_buf(opaque, stream, "write flush [%d:%d len %d]\n", bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); - - if (bytesWritten < 0) - return bytesWritten; - - totalBytesWritten += bytesWritten; - bytesLeftToWrite -= bytesWritten; - streamio->position += bytesWritten; - } - streamio->writeBufferLength = 0; - streamio->writeBufferPos = 0; - return totalBytesWritten; -} - -uLong ZCALLBACK fread_buf_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - void* buf; - uLong size; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - uInt bytesToRead = 0; - uInt bufLength = 0; - uInt bytesToCopy = 0; - uInt bytesLeftToRead = size; - uInt bytesRead = -1; - - print_buf(opaque, stream, "read [size %ld pos %lld]\n", size, streamio->position); - - if (streamio->writeBufferLength > 0) - { - print_buf(opaque, stream, "switch from write to read, not yet supported [%lld]\n", streamio->position); - } - - while (bytesLeftToRead > 0) - { - if ((streamio->readBufferLength == 0) || (streamio->readBufferPos == streamio->readBufferLength)) - { - if (streamio->readBufferLength == IOBUF_BUFFERSIZE) - { - streamio->readBufferPos = 0; - streamio->readBufferLength = 0; - } - - bytesToRead = IOBUF_BUFFERSIZE -(streamio->readBufferLength - streamio->readBufferPos); - - if (bufio->filefunc64.zread_file != NULL) - bytesRead = bufio->filefunc64.zread_file(bufio->filefunc64.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); - else - bytesRead = bufio->filefunc.zread_file(bufio->filefunc.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); - - streamio->readBufferMisses += 1; - streamio->readBufferLength += bytesRead; - streamio->position += bytesRead; - - print_buf(opaque, stream, "filled [read %d/%d buf %d:%d pos %lld]\n", bytesRead, bytesToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); - - if (bytesRead == 0) - break; - } - - if ((streamio->readBufferLength - streamio->readBufferPos) > 0) - { - bytesToCopy = min(bytesLeftToRead, (streamio->readBufferLength - streamio->readBufferPos)); - memcpy((char *)buf + bufLength, streamio->readBuffer + streamio->readBufferPos, bytesToCopy); - - bufLength += bytesToCopy; - bytesLeftToRead -= bytesToCopy; - - streamio->readBufferHits += 1; - streamio->readBufferPos += bytesToCopy; - - print_buf(opaque, stream, "emptied [copied %d remaining %d buf %d:%d pos %lld]\n", bytesToCopy, bytesLeftToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); - } - } - - return size - bytesLeftToRead; -} - -uLong ZCALLBACK fwrite_buf_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - const void* buf; - uLong size; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - uInt bytesToWrite = size; - uInt bytesLeftToWrite = size; - uInt bytesToCopy = 0; - int retVal = 0; - - print_buf(opaque, stream, "write [size %ld len %d pos %lld]\n", size, streamio->writeBufferLength, streamio->position); - - if (streamio->readBufferLength > 0) - { - streamio->position -= streamio->readBufferLength; - streamio->position += streamio->readBufferPos; - - streamio->readBufferLength = 0; - streamio->readBufferPos = 0; - - print_buf(opaque, stream, "switch from read to write [%lld]\n", streamio->position); - - if (bufio->filefunc64.zseek64_file != NULL) - retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, streamio->position, ZLIB_FILEFUNC_SEEK_SET); - else - retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, (uLong)streamio->position, ZLIB_FILEFUNC_SEEK_SET); - - if (retVal != 0) - return -1; - } - - while (bytesLeftToWrite > 0) - { - bytesToCopy = min(bytesLeftToWrite, (IOBUF_BUFFERSIZE - min(streamio->writeBufferLength, streamio->writeBufferPos))); - - if (bytesToCopy == 0) - { - if (fflush_buf(opaque, stream) <= 0) - return 0; - - continue; - } - - memcpy(streamio->writeBuffer + streamio->writeBufferPos, (char *)buf + (bytesToWrite - bytesLeftToWrite), bytesToCopy); - - print_buf(opaque, stream, "write copy [remaining %d write %d:%d len %d]\n", bytesToCopy, bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); - - bytesLeftToWrite -= bytesToCopy; - - streamio->writeBufferPos += bytesToCopy; - streamio->writeBufferHits += 1; - if (streamio->writeBufferPos > streamio->writeBufferLength) - streamio->writeBufferLength += streamio->writeBufferPos - streamio->writeBufferLength; - } - - return size - bytesLeftToWrite; -} - -ZPOS64_T ftell_buf_internal_func (opaque, stream, position) - voidpf opaque; - voidpf stream; - ZPOS64_T position; -{ - ourstream_t *streamio = (ourstream_t *)stream; - streamio->position = position; - print_buf(opaque, stream, "tell [pos %llu readpos %d writepos %d err %d]\n", streamio->position, streamio->readBufferPos, streamio->writeBufferPos, errno); - if (streamio->readBufferLength > 0) - position -= (streamio->readBufferLength - streamio->readBufferPos); - if (streamio->writeBufferLength > 0) - position += streamio->writeBufferPos; - return position; -} - -long ZCALLBACK ftell_buf_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - ZPOS64_T position = bufio->filefunc.ztell_file(bufio->filefunc.opaque, streamio->stream); - return (long)ftell_buf_internal_func(opaque, stream, position); -} - -ZPOS64_T ZCALLBACK ftell64_buf_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - ZPOS64_T position = bufio->filefunc64.ztell64_file(bufio->filefunc64.opaque, streamio->stream); - return ftell_buf_internal_func(opaque, stream, position); -} - -int fseek_buf_internal_func (opaque, stream, offset, origin) - voidpf opaque; - voidpf stream; - ZPOS64_T offset; - int origin; -{ - ourstream_t *streamio = (ourstream_t *)stream; - - print_buf(opaque, stream, "seek [origin %d offset %llu pos %lld]\n", origin, offset, streamio->position); - - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_SET: - - if (streamio->writeBufferLength > 0) - { - if ((offset >= streamio->position) && (offset <= streamio->position + streamio->writeBufferLength)) - { - streamio->writeBufferPos = (uLong)(offset - streamio->position); - return 0; - } - } - if ((streamio->readBufferLength > 0) && (offset < streamio->position) && (offset >= streamio->position - streamio->readBufferLength)) - { - streamio->readBufferPos = (uLong)(offset - (streamio->position - streamio->readBufferLength)); - return 0; - } - if (fflush_buf(opaque, stream) < 0) - return -1; - streamio->position = offset; - break; - - case ZLIB_FILEFUNC_SEEK_CUR: - - if (streamio->readBufferLength > 0) - { - if (offset <= (streamio->readBufferLength - streamio->readBufferPos)) - { - streamio->readBufferPos += (uLong)offset; - return 0; - } - offset -= (streamio->readBufferLength - streamio->readBufferPos); - streamio->position += offset; - } - if (streamio->writeBufferLength > 0) - { - if (offset <= (streamio->writeBufferLength - streamio->writeBufferPos)) - { - streamio->writeBufferPos += (uLong)offset; - return 0; - } - offset -= (streamio->writeBufferLength - streamio->writeBufferPos); - } - - if (fflush_buf(opaque, stream) < 0) - return -1; - - break; - - case ZLIB_FILEFUNC_SEEK_END: - - if (streamio->writeBufferLength > 0) - { - streamio->writeBufferPos = streamio->writeBufferLength; - return 0; - } - break; - } - - streamio->readBufferLength = 0; - streamio->readBufferPos = 0; - streamio->writeBufferLength = 0; - streamio->writeBufferPos = 0; - return 1; -} - -long ZCALLBACK fseek_buf_func (opaque, stream, offset, origin) - voidpf opaque; - voidpf stream; - uLong offset; - int origin; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - int retVal = -1; - if (bufio->filefunc.zseek_file == NULL) - return retVal; - retVal = fseek_buf_internal_func(opaque, stream, offset, origin); - if (retVal == 1) - retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, offset, origin); - return retVal; -} - -long ZCALLBACK fseek64_buf_func (opaque, stream, offset, origin) - voidpf opaque; - voidpf stream; - ZPOS64_T offset; - int origin; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - int retVal = -1; - if (bufio->filefunc64.zseek64_file == NULL) - return retVal; - retVal = fseek_buf_internal_func(opaque, stream, offset, origin); - if (retVal == 1) - retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, offset, origin); - return retVal; -} - -int ZCALLBACK fclose_buf_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - int retVal = 0; - fflush_buf(opaque, stream); - print_buf(opaque, stream, "close\n"); - if (streamio->readBufferHits + streamio->readBufferMisses > 0) - print_buf(opaque, stream, "read efficency %.02f%%\n", (streamio->readBufferHits / ((float)streamio->readBufferHits + streamio->readBufferMisses)) * 100); - if (streamio->writeBufferHits + streamio->writeBufferMisses > 0) - print_buf(opaque, stream, "write efficency %.02f%%\n", (streamio->writeBufferHits / ((float)streamio->writeBufferHits + streamio->writeBufferMisses)) * 100); - if (bufio->filefunc64.zclose_file != NULL) - retVal = bufio->filefunc64.zclose_file(bufio->filefunc64.opaque, streamio->stream); - else - retVal = bufio->filefunc.zclose_file(bufio->filefunc.opaque, streamio->stream); - free(streamio); - return retVal; -} - -int ZCALLBACK ferror_buf_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourbuffer_t *bufio = (ourbuffer_t *)opaque; - ourstream_t *streamio = (ourstream_t *)stream; - if (bufio->filefunc64.zerror_file != NULL) - return bufio->filefunc64.zerror_file(bufio->filefunc64.opaque, streamio->stream); - return bufio->filefunc.zerror_file(bufio->filefunc.opaque, streamio->stream); -} - - -void fill_buffer_filefunc (pzlib_filefunc_def, ourbuf) - zlib_filefunc_def* pzlib_filefunc_def; - ourbuffer_t *ourbuf; -{ - pzlib_filefunc_def->zopen_file = fopen_buf_func; - pzlib_filefunc_def->zopendisk_file = fopendisk_buf_func; - pzlib_filefunc_def->zread_file = fread_buf_func; - pzlib_filefunc_def->zwrite_file = fwrite_buf_func; - pzlib_filefunc_def->ztell_file = ftell_buf_func; - pzlib_filefunc_def->zseek_file = fseek_buf_func; - pzlib_filefunc_def->zclose_file = fclose_buf_func; - pzlib_filefunc_def->zerror_file = ferror_buf_func; - pzlib_filefunc_def->opaque = ourbuf; -} - -void fill_buffer_filefunc64 (pzlib_filefunc_def, ourbuf) - zlib_filefunc64_def* pzlib_filefunc_def; - ourbuffer_t *ourbuf; -{ - pzlib_filefunc_def->zopen64_file = fopen64_buf_func; - pzlib_filefunc_def->zopendisk64_file = fopendisk64_buf_func; - pzlib_filefunc_def->zread_file = fread_buf_func; - pzlib_filefunc_def->zwrite_file = fwrite_buf_func; - pzlib_filefunc_def->ztell64_file = ftell64_buf_func; - pzlib_filefunc_def->zseek64_file = fseek64_buf_func; - pzlib_filefunc_def->zclose_file = fclose_buf_func; - pzlib_filefunc_def->zerror_file = ferror_buf_func; - pzlib_filefunc_def->opaque = ourbuf; -} +/* ioapi_buf.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + This version of ioapi is designed to buffer IO. + + Copyright (C) 1998-2003 Gilles Vollant + (C) 2012-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + + +#include +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + +#include "ioapi_buf.h" + +#if defined(_WIN32) +# include +# define PRINTF _cprintf +# define VPRINTF _vcprintf +#else +# define PRINTF printf +# define VPRINTF vprintf +#endif + +//#define IOBUF_VERBOSE + +#ifdef __GNUC__ +#ifndef max +#define max(x,y) ({ \ +const typeof(x) _x = (x); \ +const typeof(y) _y = (y); \ +(void) (&_x == &_y); \ +_x > _y ? _x : _y; }) +#endif /* __GNUC__ */ + +#ifndef min +#define min(x,y) ({ \ +const typeof(x) _x = (x); \ +const typeof(y) _y = (y); \ +(void) (&_x == &_y); \ +_x < _y ? _x : _y; }) +#endif +#endif + +typedef struct ourstream_s { + char readBuffer[IOBUF_BUFFERSIZE]; + uInt readBufferLength; + uInt readBufferPos; + uInt readBufferHits; + uInt readBufferMisses; + char writeBuffer[IOBUF_BUFFERSIZE]; + uInt writeBufferLength; + uInt writeBufferPos; + uInt writeBufferHits; + uInt writeBufferMisses; + ZPOS64_T position; + voidpf stream; +} ourstream_t; + +#if defined(IOBUF_VERBOSE) +# define print_buf(o,s,f,...) print_buf_internal(o,s,f,__VA_ARGS__); +#else +# define print_buf(o,s,f,...) +#endif + +void print_buf_internal(voidpf opaque, voidpf stream, char *format, ...) +{ + ourstream_t *streamio = (ourstream_t *)stream; + va_list arglist; + PRINTF("Buf stream %p - ", streamio); + va_start(arglist, format); + VPRINTF(format, arglist); + va_end(arglist); +} + +voidpf fopen_buf_internal_func (opaque, stream, number_disk, mode) + voidpf opaque; + voidpf stream; + int number_disk; + int mode; +{ + ourstream_t *streamio = NULL; + if (stream == NULL) + return NULL; + streamio = (ourstream_t *)malloc(sizeof(ourstream_t)); + if (streamio == NULL) + return NULL; + memset(streamio, 0, sizeof(ourstream_t)); + streamio->stream = stream; + print_buf(opaque, streamio, "open [num %d mode %d]\n", number_disk, mode); + return streamio; +} + +voidpf ZCALLBACK fopen_buf_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + voidpf stream = bufio->filefunc.zopen_file(bufio->filefunc.opaque, filename, mode); + return fopen_buf_internal_func(opaque, stream, 0, mode); +} + +voidpf ZCALLBACK fopen64_buf_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + voidpf stream = bufio->filefunc64.zopen64_file(bufio->filefunc64.opaque, filename, mode); + return fopen_buf_internal_func(opaque, stream, 0, mode); +} + +voidpf ZCALLBACK fopendisk_buf_func (opaque, stream_cd, number_disk, mode) + voidpf opaque; + voidpf stream_cd; + int number_disk; + int mode; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream_cd; + voidpf *stream = bufio->filefunc.zopendisk_file(bufio->filefunc.opaque, streamio->stream, number_disk, mode); + return fopen_buf_internal_func(opaque, stream, number_disk, mode); +} + +voidpf ZCALLBACK fopendisk64_buf_func (opaque, stream_cd, number_disk, mode) + voidpf opaque; + voidpf stream_cd; + int number_disk; + int mode; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream_cd; + voidpf stream = bufio->filefunc64.zopendisk64_file(bufio->filefunc64.opaque, streamio->stream, number_disk, mode); + return fopen_buf_internal_func(opaque, stream, number_disk, mode); +} + +long fflush_buf OF((voidpf opaque, voidpf stream)); +long fflush_buf (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + uInt totalBytesWritten = 0; + uInt bytesToWrite = streamio->writeBufferLength; + uInt bytesLeftToWrite = streamio->writeBufferLength; + int bytesWritten = 0; + + while (bytesLeftToWrite > 0) + { + if (bufio->filefunc64.zwrite_file != NULL) + bytesWritten = bufio->filefunc64.zwrite_file(bufio->filefunc64.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); + else + bytesWritten = bufio->filefunc.zwrite_file(bufio->filefunc.opaque, streamio->stream, streamio->writeBuffer + (bytesToWrite - bytesLeftToWrite), bytesLeftToWrite); + + streamio->writeBufferMisses += 1; + + print_buf(opaque, stream, "write flush [%d:%d len %d]\n", bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); + + if (bytesWritten < 0) + return bytesWritten; + + totalBytesWritten += bytesWritten; + bytesLeftToWrite -= bytesWritten; + streamio->position += bytesWritten; + } + streamio->writeBufferLength = 0; + streamio->writeBufferPos = 0; + return totalBytesWritten; +} + +uLong ZCALLBACK fread_buf_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + uInt bytesToRead = 0; + uInt bufLength = 0; + uInt bytesToCopy = 0; + uInt bytesLeftToRead = size; + uInt bytesRead = -1; + + print_buf(opaque, stream, "read [size %ld pos %lld]\n", size, streamio->position); + + if (streamio->writeBufferLength > 0) + { + print_buf(opaque, stream, "switch from write to read, not yet supported [%lld]\n", streamio->position); + } + + while (bytesLeftToRead > 0) + { + if ((streamio->readBufferLength == 0) || (streamio->readBufferPos == streamio->readBufferLength)) + { + if (streamio->readBufferLength == IOBUF_BUFFERSIZE) + { + streamio->readBufferPos = 0; + streamio->readBufferLength = 0; + } + + bytesToRead = IOBUF_BUFFERSIZE -(streamio->readBufferLength - streamio->readBufferPos); + + if (bufio->filefunc64.zread_file != NULL) + bytesRead = bufio->filefunc64.zread_file(bufio->filefunc64.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); + else + bytesRead = bufio->filefunc.zread_file(bufio->filefunc.opaque, streamio->stream, streamio->readBuffer + streamio->readBufferPos, bytesToRead); + + streamio->readBufferMisses += 1; + streamio->readBufferLength += bytesRead; + streamio->position += bytesRead; + + print_buf(opaque, stream, "filled [read %d/%d buf %d:%d pos %lld]\n", bytesRead, bytesToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); + + if (bytesRead == 0) + break; + } + + if ((streamio->readBufferLength - streamio->readBufferPos) > 0) + { + bytesToCopy = min(bytesLeftToRead, (streamio->readBufferLength - streamio->readBufferPos)); + memcpy((char *)buf + bufLength, streamio->readBuffer + streamio->readBufferPos, bytesToCopy); + + bufLength += bytesToCopy; + bytesLeftToRead -= bytesToCopy; + + streamio->readBufferHits += 1; + streamio->readBufferPos += bytesToCopy; + + print_buf(opaque, stream, "emptied [copied %d remaining %d buf %d:%d pos %lld]\n", bytesToCopy, bytesLeftToRead, streamio->readBufferPos, streamio->readBufferLength, streamio->position); + } + } + + return size - bytesLeftToRead; +} + +uLong ZCALLBACK fwrite_buf_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + uInt bytesToWrite = size; + uInt bytesLeftToWrite = size; + uInt bytesToCopy = 0; + int retVal = 0; + + print_buf(opaque, stream, "write [size %ld len %d pos %lld]\n", size, streamio->writeBufferLength, streamio->position); + + if (streamio->readBufferLength > 0) + { + streamio->position -= streamio->readBufferLength; + streamio->position += streamio->readBufferPos; + + streamio->readBufferLength = 0; + streamio->readBufferPos = 0; + + print_buf(opaque, stream, "switch from read to write [%lld]\n", streamio->position); + + if (bufio->filefunc64.zseek64_file != NULL) + retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, streamio->position, ZLIB_FILEFUNC_SEEK_SET); + else + retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, (uLong)streamio->position, ZLIB_FILEFUNC_SEEK_SET); + + if (retVal != 0) + return -1; + } + + while (bytesLeftToWrite > 0) + { + bytesToCopy = min(bytesLeftToWrite, (IOBUF_BUFFERSIZE - min(streamio->writeBufferLength, streamio->writeBufferPos))); + + if (bytesToCopy == 0) + { + if (fflush_buf(opaque, stream) <= 0) + return 0; + + continue; + } + + memcpy(streamio->writeBuffer + streamio->writeBufferPos, (char *)buf + (bytesToWrite - bytesLeftToWrite), bytesToCopy); + + print_buf(opaque, stream, "write copy [remaining %d write %d:%d len %d]\n", bytesToCopy, bytesToWrite, bytesLeftToWrite, streamio->writeBufferLength); + + bytesLeftToWrite -= bytesToCopy; + + streamio->writeBufferPos += bytesToCopy; + streamio->writeBufferHits += 1; + if (streamio->writeBufferPos > streamio->writeBufferLength) + streamio->writeBufferLength += streamio->writeBufferPos - streamio->writeBufferLength; + } + + return size - bytesLeftToWrite; +} + +ZPOS64_T ftell_buf_internal_func (opaque, stream, position) + voidpf opaque; + voidpf stream; + ZPOS64_T position; +{ + ourstream_t *streamio = (ourstream_t *)stream; + streamio->position = position; + print_buf(opaque, stream, "tell [pos %llu readpos %d writepos %d err %d]\n", streamio->position, streamio->readBufferPos, streamio->writeBufferPos, errno); + if (streamio->readBufferLength > 0) + position -= (streamio->readBufferLength - streamio->readBufferPos); + if (streamio->writeBufferLength > 0) + position += streamio->writeBufferPos; + return position; +} + +long ZCALLBACK ftell_buf_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + ZPOS64_T position = bufio->filefunc.ztell_file(bufio->filefunc.opaque, streamio->stream); + return (long)ftell_buf_internal_func(opaque, stream, position); +} + +ZPOS64_T ZCALLBACK ftell64_buf_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + ZPOS64_T position = bufio->filefunc64.ztell64_file(bufio->filefunc64.opaque, streamio->stream); + return ftell_buf_internal_func(opaque, stream, position); +} + +int fseek_buf_internal_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + ZPOS64_T offset; + int origin; +{ + ourstream_t *streamio = (ourstream_t *)stream; + + print_buf(opaque, stream, "seek [origin %d offset %llu pos %lld]\n", origin, offset, streamio->position); + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_SET: + + if (streamio->writeBufferLength > 0) + { + if ((offset >= streamio->position) && (offset <= streamio->position + streamio->writeBufferLength)) + { + streamio->writeBufferPos = (uLong)(offset - streamio->position); + return 0; + } + } + if ((streamio->readBufferLength > 0) && (offset < streamio->position) && (offset >= streamio->position - streamio->readBufferLength)) + { + streamio->readBufferPos = (uLong)(offset - (streamio->position - streamio->readBufferLength)); + return 0; + } + if (fflush_buf(opaque, stream) < 0) + return -1; + streamio->position = offset; + break; + + case ZLIB_FILEFUNC_SEEK_CUR: + + if (streamio->readBufferLength > 0) + { + if (offset <= (streamio->readBufferLength - streamio->readBufferPos)) + { + streamio->readBufferPos += (uLong)offset; + return 0; + } + offset -= (streamio->readBufferLength - streamio->readBufferPos); + streamio->position += offset; + } + if (streamio->writeBufferLength > 0) + { + if (offset <= (streamio->writeBufferLength - streamio->writeBufferPos)) + { + streamio->writeBufferPos += (uLong)offset; + return 0; + } + offset -= (streamio->writeBufferLength - streamio->writeBufferPos); + } + + if (fflush_buf(opaque, stream) < 0) + return -1; + + break; + + case ZLIB_FILEFUNC_SEEK_END: + + if (streamio->writeBufferLength > 0) + { + streamio->writeBufferPos = streamio->writeBufferLength; + return 0; + } + break; + } + + streamio->readBufferLength = 0; + streamio->readBufferPos = 0; + streamio->writeBufferLength = 0; + streamio->writeBufferPos = 0; + return 1; +} + +long ZCALLBACK fseek_buf_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + int retVal = -1; + if (bufio->filefunc.zseek_file == NULL) + return retVal; + retVal = fseek_buf_internal_func(opaque, stream, offset, origin); + if (retVal == 1) + retVal = bufio->filefunc.zseek_file(bufio->filefunc.opaque, streamio->stream, offset, origin); + return retVal; +} + +long ZCALLBACK fseek64_buf_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + ZPOS64_T offset; + int origin; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + int retVal = -1; + if (bufio->filefunc64.zseek64_file == NULL) + return retVal; + retVal = fseek_buf_internal_func(opaque, stream, offset, origin); + if (retVal == 1) + retVal = bufio->filefunc64.zseek64_file(bufio->filefunc64.opaque, streamio->stream, offset, origin); + return retVal; +} + +int ZCALLBACK fclose_buf_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + int retVal = 0; + fflush_buf(opaque, stream); + print_buf(opaque, stream, "close\n"); + if (streamio->readBufferHits + streamio->readBufferMisses > 0) + print_buf(opaque, stream, "read efficency %.02f%%\n", (streamio->readBufferHits / ((float)streamio->readBufferHits + streamio->readBufferMisses)) * 100); + if (streamio->writeBufferHits + streamio->writeBufferMisses > 0) + print_buf(opaque, stream, "write efficency %.02f%%\n", (streamio->writeBufferHits / ((float)streamio->writeBufferHits + streamio->writeBufferMisses)) * 100); + if (bufio->filefunc64.zclose_file != NULL) + retVal = bufio->filefunc64.zclose_file(bufio->filefunc64.opaque, streamio->stream); + else + retVal = bufio->filefunc.zclose_file(bufio->filefunc.opaque, streamio->stream); + free(streamio); + return retVal; +} + +int ZCALLBACK ferror_buf_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourbuffer_t *bufio = (ourbuffer_t *)opaque; + ourstream_t *streamio = (ourstream_t *)stream; + if (bufio->filefunc64.zerror_file != NULL) + return bufio->filefunc64.zerror_file(bufio->filefunc64.opaque, streamio->stream); + return bufio->filefunc.zerror_file(bufio->filefunc.opaque, streamio->stream); +} + + +void fill_buffer_filefunc (pzlib_filefunc_def, ourbuf) + zlib_filefunc_def* pzlib_filefunc_def; + ourbuffer_t *ourbuf; +{ + pzlib_filefunc_def->zopen_file = fopen_buf_func; + pzlib_filefunc_def->zopendisk_file = fopendisk_buf_func; + pzlib_filefunc_def->zread_file = fread_buf_func; + pzlib_filefunc_def->zwrite_file = fwrite_buf_func; + pzlib_filefunc_def->ztell_file = ftell_buf_func; + pzlib_filefunc_def->zseek_file = fseek_buf_func; + pzlib_filefunc_def->zclose_file = fclose_buf_func; + pzlib_filefunc_def->zerror_file = ferror_buf_func; + pzlib_filefunc_def->opaque = ourbuf; +} + +void fill_buffer_filefunc64 (pzlib_filefunc_def, ourbuf) + zlib_filefunc64_def* pzlib_filefunc_def; + ourbuffer_t *ourbuf; +{ + pzlib_filefunc_def->zopen64_file = fopen64_buf_func; + pzlib_filefunc_def->zopendisk64_file = fopendisk64_buf_func; + pzlib_filefunc_def->zread_file = fread_buf_func; + pzlib_filefunc_def->zwrite_file = fwrite_buf_func; + pzlib_filefunc_def->ztell64_file = ftell64_buf_func; + pzlib_filefunc_def->zseek64_file = fseek64_buf_func; + pzlib_filefunc_def->zclose_file = fclose_buf_func; + pzlib_filefunc_def->zerror_file = ferror_buf_func; + pzlib_filefunc_def->opaque = ourbuf; +} diff --git a/libs/minizip/source/ioapi_mem.c b/libs/minizip/source/ioapi_mem.c index cf561ddf..fc0a0833 100644 --- a/libs/minizip/source/ioapi_mem.c +++ b/libs/minizip/source/ioapi_mem.c @@ -1,192 +1,192 @@ -/* ioapi_mem.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - This version of ioapi is designed to access memory rather than files. - We do use a region of memory to put data in to and take it out of. We do - not have auto-extending buffers and do not inform anyone else that the - data has been written. It is really intended for accessing a zip archive - embedded in an application such that I can write an installer with no - external files. Creation of archives has not been attempted, although - parts of the framework are present. - - Based on Unzip ioapi.c version 0.22, May 19th, 2003 - - Copyright (C) 1998-2003 Gilles Vollant - (C) 2003 Justin Fletcher - - This file is under the same license as the Unzip tool it is distributed - with. -*/ - - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" - -#include "ioapi_mem.h" - -#ifndef IOMEM_BUFFERSIZE -# define IOMEM_BUFFERSIZE (64 * 1024) -#endif - -voidpf ZCALLBACK fopen_mem_func (opaque, filename, mode) - voidpf opaque; - const char* filename; - int mode; -{ - ourmemory_t *mem = (ourmemory_t *)opaque; - if (mem == NULL) - return NULL; /* Mem structure passed in was null */ - - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - { - if (mem->grow) - { - mem->size = IOMEM_BUFFERSIZE; - mem->base = (char *)malloc(mem->size); - } - - mem->limit = 0; /* When writing we start with 0 bytes written */ - } - else - mem->limit = mem->size; - - mem->cur_offset = 0; - - return mem; -} - -voidpf ZCALLBACK fopendisk_mem_func (opaque, stream, number_disk, mode) - voidpf opaque; - voidpf stream; - int number_disk; - int mode; -{ - /* Not used */ - return NULL; -} - -uLong ZCALLBACK fread_mem_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - void* buf; - uLong size; -{ - ourmemory_t *mem = (ourmemory_t *)stream; - - if (size > mem->size - mem->cur_offset) - size = mem->size - mem->cur_offset; - - memcpy(buf, mem->base + mem->cur_offset, size); - mem->cur_offset += size; - - return size; -} - - -uLong ZCALLBACK fwrite_mem_func (opaque, stream, buf, size) - voidpf opaque; - voidpf stream; - const void* buf; - uLong size; -{ - ourmemory_t *mem = (ourmemory_t *)stream; - char *newbase = NULL; - int newmemsize = 0; - - if (size > mem->size - mem->cur_offset) - { - if (mem->grow) - { - newmemsize = mem->size; - if (size < IOMEM_BUFFERSIZE) - newmemsize += IOMEM_BUFFERSIZE; - else - newmemsize += size; - newbase = (char *)malloc(newmemsize); - memcpy(newbase, mem->base, mem->size); - free(mem->base); - mem->base = newbase; - mem->size = newmemsize; - } - else - size = mem->size - mem->cur_offset; - } - memcpy(mem->base + mem->cur_offset, buf, size); - mem->cur_offset += size; - if (mem->cur_offset > mem->limit) - mem->limit = mem->cur_offset; - - return size; -} - -long ZCALLBACK ftell_mem_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - ourmemory_t *mem = (ourmemory_t *)stream; - return mem->cur_offset; -} - -long ZCALLBACK fseek_mem_func (opaque, stream, offset, origin) - voidpf opaque; - voidpf stream; - uLong offset; - int origin; -{ - ourmemory_t *mem = (ourmemory_t *)stream; - uLong new_pos; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR: - new_pos = mem->cur_offset + offset; - break; - case ZLIB_FILEFUNC_SEEK_END: - new_pos = mem->limit + offset; - break; - case ZLIB_FILEFUNC_SEEK_SET: - new_pos = offset; - break; - default: - return -1; - } - - if (new_pos > mem->size) - return 1; /* Failed to seek that far */ - mem->cur_offset = new_pos; - return 0; -} - -int ZCALLBACK fclose_mem_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - /* Even with grow = 1, caller must always free() memory */ - return 0; -} - -int ZCALLBACK ferror_mem_func (opaque, stream) - voidpf opaque; - voidpf stream; -{ - /* We never return errors */ - return 0; -} - -void fill_memory_filefunc (pzlib_filefunc_def, ourmem) - zlib_filefunc_def* pzlib_filefunc_def; - ourmemory_t *ourmem; -{ - pzlib_filefunc_def->zopen_file = fopen_mem_func; - pzlib_filefunc_def->zopendisk_file = fopendisk_mem_func; - pzlib_filefunc_def->zread_file = fread_mem_func; - pzlib_filefunc_def->zwrite_file = fwrite_mem_func; - pzlib_filefunc_def->ztell_file = ftell_mem_func; - pzlib_filefunc_def->zseek_file = fseek_mem_func; - pzlib_filefunc_def->zclose_file = fclose_mem_func; - pzlib_filefunc_def->zerror_file = ferror_mem_func; - pzlib_filefunc_def->opaque = ourmem; -} +/* ioapi_mem.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + This version of ioapi is designed to access memory rather than files. + We do use a region of memory to put data in to and take it out of. We do + not have auto-extending buffers and do not inform anyone else that the + data has been written. It is really intended for accessing a zip archive + embedded in an application such that I can write an installer with no + external files. Creation of archives has not been attempted, although + parts of the framework are present. + + Based on Unzip ioapi.c version 0.22, May 19th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + (C) 2003 Justin Fletcher + + This file is under the same license as the Unzip tool it is distributed + with. +*/ + + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + +#include "ioapi_mem.h" + +#ifndef IOMEM_BUFFERSIZE +# define IOMEM_BUFFERSIZE (64 * 1024) +#endif + +voidpf ZCALLBACK fopen_mem_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + ourmemory_t *mem = (ourmemory_t *)opaque; + if (mem == NULL) + return NULL; /* Mem structure passed in was null */ + + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + if (mem->grow) + { + mem->size = IOMEM_BUFFERSIZE; + mem->base = (char *)malloc(mem->size); + } + + mem->limit = 0; /* When writing we start with 0 bytes written */ + } + else + mem->limit = mem->size; + + mem->cur_offset = 0; + + return mem; +} + +voidpf ZCALLBACK fopendisk_mem_func (opaque, stream, number_disk, mode) + voidpf opaque; + voidpf stream; + int number_disk; + int mode; +{ + /* Not used */ + return NULL; +} + +uLong ZCALLBACK fread_mem_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + + if (size > mem->size - mem->cur_offset) + size = mem->size - mem->cur_offset; + + memcpy(buf, mem->base + mem->cur_offset, size); + mem->cur_offset += size; + + return size; +} + + +uLong ZCALLBACK fwrite_mem_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + char *newbase = NULL; + int newmemsize = 0; + + if (size > mem->size - mem->cur_offset) + { + if (mem->grow) + { + newmemsize = mem->size; + if (size < IOMEM_BUFFERSIZE) + newmemsize += IOMEM_BUFFERSIZE; + else + newmemsize += size; + newbase = (char *)malloc(newmemsize); + memcpy(newbase, mem->base, mem->size); + free(mem->base); + mem->base = newbase; + mem->size = newmemsize; + } + else + size = mem->size - mem->cur_offset; + } + memcpy(mem->base + mem->cur_offset, buf, size); + mem->cur_offset += size; + if (mem->cur_offset > mem->limit) + mem->limit = mem->cur_offset; + + return size; +} + +long ZCALLBACK ftell_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + return mem->cur_offset; +} + +long ZCALLBACK fseek_mem_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + uLong new_pos; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR: + new_pos = mem->cur_offset + offset; + break; + case ZLIB_FILEFUNC_SEEK_END: + new_pos = mem->limit + offset; + break; + case ZLIB_FILEFUNC_SEEK_SET: + new_pos = offset; + break; + default: + return -1; + } + + if (new_pos > mem->size) + return 1; /* Failed to seek that far */ + mem->cur_offset = new_pos; + return 0; +} + +int ZCALLBACK fclose_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + /* Even with grow = 1, caller must always free() memory */ + return 0; +} + +int ZCALLBACK ferror_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + /* We never return errors */ + return 0; +} + +void fill_memory_filefunc (pzlib_filefunc_def, ourmem) + zlib_filefunc_def* pzlib_filefunc_def; + ourmemory_t *ourmem; +{ + pzlib_filefunc_def->zopen_file = fopen_mem_func; + pzlib_filefunc_def->zopendisk_file = fopendisk_mem_func; + pzlib_filefunc_def->zread_file = fread_mem_func; + pzlib_filefunc_def->zwrite_file = fwrite_mem_func; + pzlib_filefunc_def->ztell_file = ftell_mem_func; + pzlib_filefunc_def->zseek_file = fseek_mem_func; + pzlib_filefunc_def->zclose_file = fclose_mem_func; + pzlib_filefunc_def->zerror_file = ferror_mem_func; + pzlib_filefunc_def->opaque = ourmem; +} diff --git a/libs/minizip/source/tools.cpp b/libs/minizip/source/tools.cpp index 5c2fee5a..adc6c25d 100644 --- a/libs/minizip/source/tools.cpp +++ b/libs/minizip/source/tools.cpp @@ -1,145 +1,145 @@ -#include "tools.h" -#include "defs.h" -#include -#include - -#include - -#include - -#if defined(WIN32) && !defined(CYGWIN) -# include "tps/dirent.h" -# include "tps/dirent.c" -#else -# include -# include -# include -#endif /* WIN32 */ - - - -namespace zipper { - - /* calculate the CRC32 of a file, - because to encrypt a file, we need known the CRC32 of the file before */ - - void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned long& result_crc) - { - unsigned long calculate_crc = 0; - unsigned long size_read = 0; - unsigned long total_read = 0; - - do { - input_stream.read(buff.data(), buff.size()); - size_read = (unsigned long)input_stream.gcount(); - - if (size_read > 0) - calculate_crc = crc32(calculate_crc, (const unsigned char*)buff.data(), size_read); - - total_read += size_read; - - } while (size_read > 0); - - input_stream.seekg(0); - result_crc = calculate_crc; - } - - bool isLargeFile(std::istream& input_stream) - { - ZPOS64_T pos = 0; - input_stream.seekg(0, std::ios::end); - pos = input_stream.tellg(); - input_stream.seekg(0); - - return pos >= 0xffffffff; - } - - bool checkFileExists(const std::string& filename) - { - return CDirEntry::exist(filename); - } - - bool makedir(const std::string& newdir) - { - return CDirEntry::createDir(newdir); - } - - void removeFolder(const std::string& foldername) - { - if (!CDirEntry::remove(foldername)) - { - std::vector files = filesFromDirectory(foldername); - std::vector::iterator it = files.begin(); - for (; it != files.end(); ++it) - { - if (isDirectory(*it) && *it != foldername) - removeFolder(*it); - else - std::remove(it->c_str()); - } - CDirEntry::remove(foldername); - } - } - - bool isDirectory(const std::string& path) - { - return CDirEntry::isDir(path); - } - - std::string parentDirectory(const std::string& filepath) - { - return CDirEntry::dirName(filepath); - } - - std::string currentPath() - { - char buffer[1024]; - getcwd(buffer, 1024); - std::string result(buffer); - return result; - - } - - - std::vector filesFromDirectory(const std::string& path) - { - std::vector files; - DIR* dir; - struct dirent* entry; - - dir = opendir(path.c_str()); - - if (dir == NULL) - { - return files; - } - - for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) - { - std::string filename(entry->d_name); - - if (filename == "." || filename == "..") continue; - - if (CDirEntry::isDir(path + CDirEntry::Separator + filename)) - { - std::vector moreFiles = filesFromDirectory(path + CDirEntry::Separator + filename); - std::copy(moreFiles.begin(), moreFiles.end(), std::back_inserter(files)); - continue; - } - - - files.push_back(path + CDirEntry::Separator + filename); - } - - closedir(dir); - - - return files; - } - - std::string fileNameFromPath(const std::string& fullPath) - { - return CDirEntry::fileName(fullPath); - } - -} +#include "tools.h" +#include "defs.h" +#include +#include + +#include + +#include + +#if defined(WIN32) && !defined(CYGWIN) +# include "tps/dirent.h" +# include "tps/dirent.c" +#else +# include +# include +# include +#endif /* WIN32 */ + + + +namespace zipper { + + /* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ + + void getFileCrc(std::istream& input_stream, std::vector& buff, unsigned long& result_crc) + { + unsigned long calculate_crc = 0; + unsigned long size_read = 0; + unsigned long total_read = 0; + + do { + input_stream.read(buff.data(), buff.size()); + size_read = (unsigned long)input_stream.gcount(); + + if (size_read > 0) + calculate_crc = crc32(calculate_crc, (const unsigned char*)buff.data(), size_read); + + total_read += size_read; + + } while (size_read > 0); + + input_stream.seekg(0); + result_crc = calculate_crc; + } + + bool isLargeFile(std::istream& input_stream) + { + ZPOS64_T pos = 0; + input_stream.seekg(0, std::ios::end); + pos = input_stream.tellg(); + input_stream.seekg(0); + + return pos >= 0xffffffff; + } + + bool checkFileExists(const std::string& filename) + { + return CDirEntry::exist(filename); + } + + bool makedir(const std::string& newdir) + { + return CDirEntry::createDir(newdir); + } + + void removeFolder(const std::string& foldername) + { + if (!CDirEntry::remove(foldername)) + { + std::vector files = filesFromDirectory(foldername); + std::vector::iterator it = files.begin(); + for (; it != files.end(); ++it) + { + if (isDirectory(*it) && *it != foldername) + removeFolder(*it); + else + std::remove(it->c_str()); + } + CDirEntry::remove(foldername); + } + } + + bool isDirectory(const std::string& path) + { + return CDirEntry::isDir(path); + } + + std::string parentDirectory(const std::string& filepath) + { + return CDirEntry::dirName(filepath); + } + + std::string currentPath() + { + char buffer[1024]; + getcwd(buffer, 1024); + std::string result(buffer); + return result; + + } + + + std::vector filesFromDirectory(const std::string& path) + { + std::vector files; + DIR* dir; + struct dirent* entry; + + dir = opendir(path.c_str()); + + if (dir == NULL) + { + return files; + } + + for (entry = readdir(dir); entry != NULL; entry = readdir(dir)) + { + std::string filename(entry->d_name); + + if (filename == "." || filename == "..") continue; + + if (CDirEntry::isDir(path + CDirEntry::Separator + filename)) + { + std::vector moreFiles = filesFromDirectory(path + CDirEntry::Separator + filename); + std::copy(moreFiles.begin(), moreFiles.end(), std::back_inserter(files)); + continue; + } + + + files.push_back(path + CDirEntry::Separator + filename); + } + + closedir(dir); + + + return files; + } + + std::string fileNameFromPath(const std::string& fullPath) + { + return CDirEntry::fileName(fullPath); + } + +} diff --git a/libs/minizip/source/unzip.c b/libs/minizip/source/unzip.c index 8b63bcd8..42d73696 100644 --- a/libs/minizip/source/unzip.c +++ b/libs/minizip/source/unzip.c @@ -1,1890 +1,1890 @@ -/* unzip.c -- IO for uncompress .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications of Unzip for Zip64 - Copyright (C) 2007-2008 Even Rouault - Modifications for Zip64 support on both zip and unzip - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - Modifications for AES, PKWARE disk spanning - Copyright (C) 2010-2014 Nathan Moinvaziri - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#include -#include -#include - -/*#ifndef NOUNCRYPT -# define NOUNCRYPT -#endif*/ - -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - -#ifdef HAVE_AES -# define AES_METHOD (99) -# define AES_PWVERIFYSIZE (2) -# define AES_MAXSALTLENGTH (16) -# define AES_AUTHCODESIZE (10) -# define AES_HEADERSIZE (11) -# define AES_KEYSIZE(mode) (64 + (mode * 64)) - -# include "aes/aes.h" -# include "aes/fileenc.h" -#endif -#ifndef NOUNCRYPT -# include "crypt.h" -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#define DISKHEADERMAGIC (0x08074b50) -#define LOCALHEADERMAGIC (0x04034b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) -#define ZIP64ENDHEADERMAGIC (0x06064b50) -#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ -#define SIZEZIPLOCALHEADER (0x1e) - -#ifndef BUFREADCOMMENT -# define BUFREADCOMMENT (0x400) -#endif - -#ifndef UNZ_BUFSIZE -# define UNZ_BUFSIZE (64 * 1024) -#endif -#ifndef UNZ_MAXFILENAMEINZIP -# define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -const char unz_copyright[] = - " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info64_internal_s -{ - ZPOS64_T offset_curfile; /* relative offset of local header 8 bytes */ - ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ -#ifdef HAVE_AES - uLong aes_encryption_mode; - uLong aes_compression_method; - uLong aes_version; -#endif -} unz_file_info64_internal; - -/* file_in_zip_read_info_s contain internal information about a file in zipfile */ -typedef struct -{ - Bytef *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - -#ifdef HAVE_BZIP2 - bz_stream bstream; /* bzLib stream structure for bziped */ -#endif -#ifdef HAVE_AES - fcrypt_ctx aes_ctx; -#endif - - ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek */ - uLong stream_initialised; /* flag set if stream structure is initialised */ - - ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ - ZPOS64_T pos_local_extrafield; /* position in the local extra field in read */ - ZPOS64_T total_out_64; - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ - ZPOS64_T rest_read_uncompressed; /* number of byte to be obtained after decomp */ - - zlib_filefunc64_32_def z_filefunc; - - voidpf filestream; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ - int raw; -} file_in_zip64_read_info_s; - -/* unz64_s contain internal information about the zipfile */ -typedef struct -{ - zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structure of the current zipfile */ - voidpf filestream_with_CD; /* io structure of the disk with the central directory */ - unz_global_info64 gi; /* public global information */ - ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ - ZPOS64_T num_file; /* number of the current file in the zipfile*/ - ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ - ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ - ZPOS64_T central_pos; /* position of the beginning of the central dir*/ - uLong number_disk; /* number of the current disk, used for spanning ZIP*/ - ZPOS64_T size_central_dir; /* size of the central directory */ - ZPOS64_T offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info64 cur_file_info; /* public info about the current file in zip*/ - unz_file_info64_internal cur_file_info_internal; - /* private info about it*/ - file_in_zip64_read_info_s* pfile_in_zip_read; - /* structure about the current file if we are decompressing it */ - int isZip64; /* is the current file zip64 */ -#ifndef NOUNCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; -#endif -} unz64_s; - -/* Translate date/time from Dos format to tm_unz (readable more easily) */ -local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) -{ - ZPOS64_T uDate = (ZPOS64_T)(ulDosDate>>16); - - ptm->tm_mday = (uInt)(uDate&0x1f); - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1); - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980); - ptm->tm_hour = (uInt)((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt)((ulDosDate&0x7E0)/0x20); - ptm->tm_sec = (uInt)(2*(ulDosDate&0x1f)); - -#define unz64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) - if (!unz64local_in_range(0, 11, ptm->tm_mon) || - !unz64local_in_range(1, 31, ptm->tm_mday) || - !unz64local_in_range(0, 23, ptm->tm_hour) || - !unz64local_in_range(0, 59, ptm->tm_min) || - !unz64local_in_range(0, 59, ptm->tm_sec)) - /* Invalid date stored, so don't return it. */ - memset(ptm, 0, sizeof(tm_unz)); -#undef unz64local_in_range -} - -/* Read a byte from a gz_stream; Return EOF for end of file. */ -local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); - if (err == 1) - { - *pi = (int)c; - return UNZ_OK; - } - if (ZERROR64(*pzlib_filefunc_def, filestream)) - return UNZ_ERRNO; - return UNZ_EOF; -} - -local int unz64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); -local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) -{ - uLong x; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (uLong)i; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((uLong)i)<<8; - - if (err == UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); -local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) -{ - uLong x; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (uLong)i; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((uLong)i)<<8; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((uLong)i)<<16; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((uLong)i)<<24; - - if (err == UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); -local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) -{ - ZPOS64_T x; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (ZPOS64_T)i; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<8; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<16; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<24; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<32; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<40; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<48; - if (err == UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); - x |= ((ZPOS64_T)i)<<56; - - if (err == UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -/* Locate the Central directory of a zip file (at the end, just before the global comment) */ -local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); -local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T file_size; - ZPOS64_T back_read = 4; - ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ - ZPOS64_T pos_found = 0; - uLong read_size; - ZPOS64_T read_pos; - int i; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT + 4); - if (buf == NULL) - return 0; - - if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) - { - TRYFREE(buf); - return 0; - } - - file_size = ZTELL64(*pzlib_filefunc_def, filestream); - - if (max_back > file_size) - max_back = file_size; - - while (back_read < max_back) - { - if (back_read + BUFREADCOMMENT > max_back) - back_read = max_back; - else - back_read += BUFREADCOMMENT; - - read_pos = file_size - back_read; - read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? - (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); - - if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - break; - if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) - break; - - for (i = (int)read_size-3; (i--) > 0;) - if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) && - ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) && - ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) && - ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff))) - { - pos_found = read_pos+i; - break; - } - - if (pos_found != 0) - break; - } - TRYFREE(buf); - return pos_found; -} - -/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T unz64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - const ZPOS64_T endcentraloffset)); -local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - const ZPOS64_T endcentraloffset) -{ - ZPOS64_T offset; - uLong uL; - - /* Zip64 end of central directory locator */ - if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) - return 0; - - /* read locator signature */ - if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) - return 0; - if (uL != ZIP64ENDLOCHEADERMAGIC) - return 0; - /* number of the disk with the start of the zip64 end of central directory */ - if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) - return 0; - /* relative offset of the zip64 end of central directory record */ - if (unz64local_getLong64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK) - return 0; - /* total number of disks */ - if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) - return 0; - /* Goto end of central directory record */ - if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) - return 0; - /* the signature */ - if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) - return 0; - if (uL != ZIP64ENDHEADERMAGIC) - return 0; - - return offset; -} - -local unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) -{ - unz64_s us; - unz64_s *s; - ZPOS64_T central_pos; - uLong uL; - voidpf filestream = NULL; - ZPOS64_T number_entry_CD; - int err = UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - us.filestream = NULL; - us.filestream_with_CD = NULL; - us.z_filefunc.zseek32_file = NULL; - us.z_filefunc.ztell32_file = NULL; - if (pzlib_filefunc64_32_def == NULL) - fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); - else - us.z_filefunc = *pzlib_filefunc64_32_def; - - us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); - - if (us.filestream == NULL) - return NULL; - - us.filestream_with_CD = us.filestream; - us.isZip64 = 0; - - /* Use unz64local_SearchCentralDir first. Only based on the result - is it necessary to locate the unz64local_SearchCentralDir64 */ - central_pos = unz64local_SearchCentralDir(&us.z_filefunc, us.filestream); - if (central_pos) - { - if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = UNZ_ERRNO; - - /* the signature, already checked */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - /* number of this disk */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - us.number_disk = uL; - /* number of the disk with the start of the central directory */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,& uL) != UNZ_OK) - err = UNZ_ERRNO; - us.gi.number_disk_with_CD = uL; - /* total number of entries in the central directory on this disk */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - us.gi.number_entry = uL; - /* total number of entries in the central directory */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - number_entry_CD = uL; - if (number_entry_CD != us.gi.number_entry) - err = UNZ_BADZIPFILE; - /* size of the central directory */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - us.size_central_dir = uL; - /* offset of start of central directory with respect to the starting disk number */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - us.offset_central_dir = uL; - /* zipfile comment length */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK) - err = UNZ_ERRNO; - - if ((err == UNZ_OK) && - ((us.gi.number_entry == 0xffff) || (us.size_central_dir == 0xffff) || (us.offset_central_dir == 0xffffffff))) - { - /* Format should be Zip64, as the central directory or file size is too large */ - central_pos = unz64local_SearchCentralDir64(&us.z_filefunc, us.filestream, central_pos); - if (central_pos) - { - ZPOS64_T uL64; - - us.isZip64 = 1; - - if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = UNZ_ERRNO; - - /* the signature, already checked */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - /* size of zip64 end of central directory record */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream, &uL64) != UNZ_OK) - err = UNZ_ERRNO; - /* version made by */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - /* version needed to extract */ - if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - /* number of this disk */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK) - err = UNZ_ERRNO; - /* number of the disk with the start of the central directory */ - if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK) - err = UNZ_ERRNO; - /* total number of entries in the central directory on this disk */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK) - err = UNZ_ERRNO; - /* total number of entries in the central directory */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK) - err = UNZ_ERRNO; - if (number_entry_CD != us.gi.number_entry) - err = UNZ_BADZIPFILE; - /* size of the central directory */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK) - err = UNZ_ERRNO; - /* offset of start of central directory with respect to the starting disk number */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK) - err = UNZ_ERRNO; - } - else - err = UNZ_BADZIPFILE; - } - } - else - err = UNZ_ERRNO; - - if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir)) - err = UNZ_BADZIPFILE; - - if (err != UNZ_OK) - { - ZCLOSE64(us.z_filefunc, us.filestream); - return NULL; - } - - if (us.gi.number_disk_with_CD == 0) - { - /* If there is only one disk open another stream so we don't have to seek between the CD - and the file headers constantly */ - filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); - if (filestream != NULL) - us.filestream = filestream; - } - - /* Hack for zip files that have no respect for zip64 - if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff)) - us.offset_central_dir = central_pos - us.size_central_dir;*/ - - us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir); - us.central_pos = central_pos; - us.pfile_in_zip_read = NULL; - - s = (unz64_s*)ALLOC(sizeof(unz64_s)); - if (s != NULL) - { - *s = us; - unzGoToFirstFile((unzFile)s); - } - return (unzFile)s; -} - -extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def* pzlib_filefunc32_def) -{ - if (pzlib_filefunc32_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); - return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); - } - return unzOpenInternal(path, NULL); -} - -extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def* pzlib_filefunc_def) -{ - if (pzlib_filefunc_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; - zlib_filefunc64_32_def_fill.ztell32_file = NULL; - zlib_filefunc64_32_def_fill.zseek32_file = NULL; - return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); - } - return unzOpenInternal(path, NULL); -} - -extern unzFile ZEXPORT unzOpen(const char *path) -{ - return unzOpenInternal(path, NULL); -} - -extern unzFile ZEXPORT unzOpen64(const void *path) -{ - return unzOpenInternal(path, NULL); -} - -extern int ZEXPORT unzClose(unzFile file) -{ - unz64_s* s; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) - ZCLOSE64(s->z_filefunc, s->filestream); - if (s->filestream_with_CD != NULL) - ZCLOSE64(s->z_filefunc, s->filestream_with_CD); - - s->filestream = NULL; - s->filestream_with_CD = NULL; - TRYFREE(s); - return UNZ_OK; -} - -/* Goto to the next available disk for spanned archives */ -local int unzGoToNextDisk OF((unzFile file)); -local int unzGoToNextDisk(unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - uLong number_disk_next = 0; - - s = (unz64_s*)file; - if (s == NULL) - return UNZ_PARAMERROR; - pfile_in_zip_read_info = s->pfile_in_zip_read; - number_disk_next = s->number_disk; - - if ((pfile_in_zip_read_info != NULL) && (pfile_in_zip_read_info->rest_read_uncompressed > 0)) - /* We are currently reading a file and we need the next sequential disk */ - number_disk_next += 1; - else - /* Goto the disk for the current file */ - number_disk_next = s->cur_file_info.disk_num_start; - - if (number_disk_next != s->number_disk) - { - /* Switch disks */ - if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) - ZCLOSE64(s->z_filefunc, s->filestream); - - if (number_disk_next == s->gi.number_disk_with_CD) - { - s->filestream = s->filestream_with_CD; - } - else - { - s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next, - ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); - } - - if (s->filestream == NULL) - return UNZ_ERRNO; - - s->number_disk = number_disk_next; - } - - return UNZ_OK; -} - -extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) -{ - unz64_s* s; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - /* to do : check if number_entry is not truncated */ - pglobal_info32->number_entry = (uLong)s->gi.number_entry; - pglobal_info32->size_comment = s->gi.size_comment; - pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD; - return UNZ_OK; -} - -extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) -{ - unz64_s* s; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - *pglobal_info = s->gi; - return UNZ_OK; -} - -extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uLong comment_size) -{ - unz64_s* s; - uLong bytes_to_read = comment_size; - if (file == NULL) - return (int)UNZ_PARAMERROR; - s = (unz64_s*)file; - - if (bytes_to_read > s->gi.size_comment) - bytes_to_read = s->gi.size_comment; - - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0) - return UNZ_ERRNO; - - if (bytes_to_read>0) - { - *comment = 0; - if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read) - return UNZ_ERRNO; - } - - if ((comment != NULL) && (comment_size > s->gi.size_comment)) - *(comment+s->gi.size_comment) = 0; - return (int)bytes_to_read; -} - -/* Get Info about the current file in the zipfile, with internal only info */ -local int unz64local_GetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info, - unz_file_info64_internal *pfile_info_internal, char *filename, uLong filename_size, void *extrafield, - uLong extrafield_size, char *comment, uLong comment_size) -{ - unz64_s* s; - unz_file_info64 file_info; - unz_file_info64_internal file_info_internal; - ZPOS64_T bytes_to_read; - int err = UNZ_OK; - uLong uMagic; - long lSeek = 0; - ZPOS64_T current_pos = 0; - uLong acc = 0; - uLong uL; - ZPOS64_T uL64; - - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, - s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = UNZ_ERRNO; - - /* Check the magic */ - if (err == UNZ_OK) - { - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uMagic) != UNZ_OK) - err = UNZ_ERRNO; - else if (uMagic != CENTRALHEADERMAGIC) - err = UNZ_BADZIPFILE; - } - - /* Read central directory header */ - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.dosDate) != UNZ_OK) - err = UNZ_ERRNO; - unz64local_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - file_info.compressed_size = uL; - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - file_info.uncompressed_size = uL; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK) - err = UNZ_ERRNO; - /* Relative offset of local header */ - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - - file_info.size_file_extra_internal = 0; - file_info.disk_offset = uL; - file_info_internal.offset_curfile = uL; -#ifdef HAVE_AES - file_info_internal.aes_compression_method = 0; - file_info_internal.aes_encryption_mode = 0; - file_info_internal.aes_version = 0; -#endif - - lSeek += file_info.size_filename; - - if ((err == UNZ_OK) && (filename != NULL)) - { - if (file_info.size_filename < filename_size) - { - *(filename+file_info.size_filename) = 0; - bytes_to_read = file_info.size_filename; - } - else - bytes_to_read = filename_size; - - if ((file_info.size_filename > 0) && (filename_size > 0)) - if (ZREAD64(s->z_filefunc, s->filestream_with_CD,filename, (uLong)bytes_to_read) != bytes_to_read) - err = UNZ_ERRNO; - lSeek -= (uLong)bytes_to_read; - } - - /* Read extrafield */ - if ((err == UNZ_OK) && (extrafield != NULL)) - { - if (file_info.size_file_extra < extrafield_size) - bytes_to_read = file_info.size_file_extra; - else - bytes_to_read = extrafield_size; - - if (lSeek != 0) - { - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) - lSeek=0; - else - err = UNZ_ERRNO; - } - - if ((file_info.size_file_extra > 0) && (extrafield_size > 0)) - if (ZREAD64(s->z_filefunc, s->filestream_with_CD, extrafield, (uLong)bytes_to_read) != bytes_to_read) - err = UNZ_ERRNO; - lSeek += file_info.size_file_extra - (uLong)bytes_to_read; - } - else - lSeek += file_info.size_file_extra; - - if ((err == UNZ_OK) && (file_info.size_file_extra != 0)) - { - if (lSeek != 0) - { - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) - lSeek=0; - else - err = UNZ_ERRNO; - } - - /* We are going to parse the extra field so we need to move back */ - current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD); - if (current_pos < file_info.size_file_extra) - err = UNZ_ERRNO; - current_pos -= file_info.size_file_extra; - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = UNZ_ERRNO; - - while((err != UNZ_ERRNO) && (acc < file_info.size_file_extra)) - { - uLong headerid; - uLong datasize; - - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &headerid) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &datasize) != UNZ_OK) - err = UNZ_ERRNO; - - /* ZIP64 extra fields */ - if (headerid == 0x0001) - { - /* Subtract size of ZIP64 field, since ZIP64 is handled internally */ - file_info.size_file_extra_internal += 2 + 2 + datasize; - - if (file_info.uncompressed_size == 0xffffffff) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK) - err = UNZ_ERRNO; - } - if (file_info.compressed_size == 0xffffffff) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK) - err = UNZ_ERRNO; - } - if (file_info_internal.offset_curfile == 0xffffffff) - { - /* Relative Header offset */ - if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &uL64) != UNZ_OK) - err = UNZ_ERRNO; - file_info_internal.offset_curfile = uL64; - file_info.disk_offset = uL64; - } - if (file_info.disk_num_start == 0xffffffff) - { - /* Disk Start Number */ - if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) - err = UNZ_ERRNO; - } - } -#ifdef HAVE_AES - /* AES header */ - else if (headerid == 0x9901) - { - /* Subtract size of AES field, since AES is handled internally */ - file_info.size_file_extra_internal += 2 + 2 + datasize; - - /* Verify version info */ - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - /* Support AE-1 and AE-2 */ - if (uL != 1 && uL != 2) - err = UNZ_ERRNO; - file_info_internal.aes_version = uL; - if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - if ((char)uL != 'A') - err = UNZ_ERRNO; - if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - if ((char)uL != 'E') - err = UNZ_ERRNO; - /* Get AES encryption strength and actual compression method */ - if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - file_info_internal.aes_encryption_mode = uL; - if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) - err = UNZ_ERRNO; - file_info_internal.aes_compression_method = uL; - } -#endif - else - { - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,datasize, ZLIB_FILEFUNC_SEEK_CUR) != 0) - err = UNZ_ERRNO; - } - - acc += 2 + 2 + datasize; - } - } - - if (file_info.disk_num_start == s->gi.number_disk_with_CD) - file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile; - else - file_info_internal.byte_before_the_zipfile = 0; - - if ((err == UNZ_OK) && (comment != NULL)) - { - if (file_info.size_file_comment < comment_size) - { - *(comment+file_info.size_file_comment) = 0; - bytes_to_read = file_info.size_file_comment; - } - else - bytes_to_read = comment_size; - - if (lSeek != 0) - { - if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) != 0) - err = UNZ_ERRNO; - } - - if ((file_info.size_file_comment > 0) && (comment_size > 0)) - if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, (uLong)bytes_to_read) != bytes_to_read) - err = UNZ_ERRNO; - lSeek += file_info.size_file_comment - (uLong)bytes_to_read; - } - else - lSeek += file_info.size_file_comment; - - if ((err == UNZ_OK) && (pfile_info != NULL)) - *pfile_info = file_info; - - if ((err == UNZ_OK) && (pfile_info_internal != NULL)) - *pfile_info_internal = file_info_internal; - - return err; -} - -extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info * pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size) -{ - unz_file_info64 file_info64; - int err; - - err = unz64local_GetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size, - extrafield, extrafield_size, comment, comment_size); - - if ((err == UNZ_OK) && (pfile_info != NULL)) - { - pfile_info->version = file_info64.version; - pfile_info->version_needed = file_info64.version_needed; - pfile_info->flag = file_info64.flag; - pfile_info->compression_method = file_info64.compression_method; - pfile_info->dosDate = file_info64.dosDate; - pfile_info->crc = file_info64.crc; - - pfile_info->size_filename = file_info64.size_filename; - pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal; - pfile_info->size_file_comment = file_info64.size_file_comment; - - pfile_info->disk_num_start = file_info64.disk_num_start; - pfile_info->internal_fa = file_info64.internal_fa; - pfile_info->external_fa = file_info64.external_fa; - - pfile_info->tmu_date = file_info64.tmu_date, - - pfile_info->compressed_size = (uLong)file_info64.compressed_size; - pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; - - } - return err; -} - -extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size) -{ - return unz64local_GetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size, - extrafield, extrafield_size, comment,comment_size); -} - -/* Read the local header of the current zipfile. Check the coherency of the local header and info in the - end of central directory about this file store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) */ -local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, ZPOS64_T *poffset_local_extrafield, - uInt *psize_local_extrafield) -{ - uLong uMagic, uL, uFlags; - uLong size_filename; - uLong size_extra_field; - int err = UNZ_OK; - int compression_method = 0; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - err = unzGoToNextDisk((unzFile)s); - if (err != UNZ_OK) - return err; - - if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile + - s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - return UNZ_ERRNO; - - if (err == UNZ_OK) - { - if (unz64local_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) - err = UNZ_ERRNO; - else if (uMagic != LOCALHEADERMAGIC) - err = UNZ_BADZIPFILE; - } - - if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK) - err = UNZ_ERRNO; - if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) - err = UNZ_ERRNO; - else if ((err == UNZ_OK) && (uL != s->cur_file_info.compression_method)) - err = UNZ_BADZIPFILE; - - compression_method = (int)s->cur_file_info.compression_method; -#ifdef HAVE_AES - if (compression_method == AES_METHOD) - compression_method = (int)s->cur_file_info_internal.aes_compression_method; -#endif - - if ((err == UNZ_OK) && (compression_method != 0) && -#ifdef HAVE_BZIP2 - (compression_method != Z_BZIP2ED) && -#endif - (compression_method != Z_DEFLATED)) - err = UNZ_BADZIPFILE; - - if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* date/time */ - err = UNZ_ERRNO; - if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* crc */ - err = UNZ_ERRNO; - else if ((err == UNZ_OK) && (uL != s->cur_file_info.crc) && ((uFlags & 8) == 0)) - err = UNZ_BADZIPFILE; - if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size compr */ - err = UNZ_ERRNO; - else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) - err = UNZ_BADZIPFILE; - if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size uncompr */ - err = UNZ_ERRNO; - else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) - err = UNZ_BADZIPFILE; - if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK) - err = UNZ_ERRNO; - else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) - err = UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK) - err = UNZ_ERRNO; - *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password) -{ - int err = UNZ_OK; - int compression_method; - uInt iSizeVar; - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - ZPOS64_T offset_local_extrafield; - uInt size_local_extrafield; -#ifndef NOUNCRYPT - char source[12]; -#else - if (password != NULL) - return UNZ_PARAMERROR; -#endif - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unz64local_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); - if (pfile_in_zip_read_info == NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer = (Bytef*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield = 0; - pfile_in_zip_read_info->raw = raw; - - if (pfile_in_zip_read_info->read_buffer == NULL) - { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised = 0; - - compression_method = (int)s->cur_file_info.compression_method; -#ifdef HAVE_AES - if (compression_method == AES_METHOD) - compression_method = (int)s->cur_file_info_internal.aes_compression_method; -#endif - - if (method != NULL) - *method = compression_method; - - if (level != NULL) - { - *level = 6; - switch (s->cur_file_info.flag & 0x06) - { - case 6 : *level = 1; break; - case 4 : *level = 2; break; - case 2 : *level = 9; break; - } - } - - if ((compression_method != 0) && -#ifdef HAVE_BZIP2 - (compression_method != Z_BZIP2ED) && -#endif - (compression_method != Z_DEFLATED)) - err = UNZ_BADZIPFILE; - - pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; - pfile_in_zip_read_info->crc32 = 0; - pfile_in_zip_read_info->total_out_64 = 0; - pfile_in_zip_read_info->compression_method = compression_method; - pfile_in_zip_read_info->filestream = s->filestream; - pfile_in_zip_read_info->z_filefunc = s->z_filefunc; - if (s->number_disk == s->gi.number_disk_with_CD) - pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; - else - pfile_in_zip_read_info->byte_before_the_zipfile = 0; - pfile_in_zip_read_info->stream.total_out = 0; - pfile_in_zip_read_info->stream.total_in = 0; - pfile_in_zip_read_info->stream.next_in = NULL; - - if (!raw) - { - if (compression_method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; - pfile_in_zip_read_info->bstream.bzfree = (free_func)0; - pfile_in_zip_read_info->bstream.opaque = (voidpf)0; - pfile_in_zip_read_info->bstream.state = (voidpf)0; - - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - pfile_in_zip_read_info->stream.next_in = (voidpf)0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } -#else - pfile_in_zip_read_info->raw=1; -#endif - } - else if (compression_method == Z_DEFLATED) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)s; - pfile_in_zip_read_info->stream.next_in = 0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised = Z_DEFLATED; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - } - - pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; - pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; - pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - -#ifndef NOUNCRYPT - if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0)) - { - if (ZSEEK64(s->z_filefunc, s->filestream, - s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET) != 0) - return UNZ_INTERNALERROR; -#ifdef HAVE_AES - if (s->cur_file_info.compression_method == AES_METHOD) - { - unsigned char passverify[AES_PWVERIFYSIZE]; - unsigned char saltvalue[AES_MAXSALTLENGTH]; - uInt saltlength; - - if ((s->cur_file_info_internal.aes_encryption_mode < 1) || - (s->cur_file_info_internal.aes_encryption_mode > 3)) - return UNZ_INTERNALERROR; - - saltlength = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode); - - if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength) - return UNZ_INTERNALERROR; - if (ZREAD64(s->z_filefunc, s->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) - return UNZ_INTERNALERROR; - - fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, password, strlen(password), saltvalue, - passverify, &s->pfile_in_zip_read->aes_ctx); - - pfile_in_zip_read_info->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE; - pfile_in_zip_read_info->rest_read_compressed -= AES_AUTHCODESIZE; - - s->pfile_in_zip_read->pos_in_zipfile += saltlength + AES_PWVERIFYSIZE; - } - else -#endif - { - int i; - s->pcrc_32_tab = (const unsigned long*)get_crc_table(); - init_keys(password, s->keys, s->pcrc_32_tab); - - if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12) - return UNZ_INTERNALERROR; - - for (i = 0; i < 12; i++) - zdecode(s->keys, s->pcrc_32_tab, source[i]); - - pfile_in_zip_read_info->rest_read_compressed -= 12; - - s->pfile_in_zip_read->pos_in_zipfile += 12; - } - } -#endif - - return UNZ_OK; -} - -extern int ZEXPORT unzOpenCurrentFile(unzFile file) -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); -} - -extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, password); -} - -extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) -{ - return unzOpenCurrentFile3(file, method, level, raw, NULL); -} - -/* Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if some bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) -{ - int err = UNZ_OK; - uInt read = 0; - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - pfile_in_zip_read_info = s->pfile_in_zip_read; - - if (pfile_in_zip_read_info == NULL) - return UNZ_PARAMERROR; - if (pfile_in_zip_read_info->read_buffer == NULL) - return UNZ_END_OF_LIST_OF_FILE; - if (len == 0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if (pfile_in_zip_read_info->raw) - { - if (len > pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in) - pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed + - pfile_in_zip_read_info->stream.avail_in; - } - else - { - if (len > pfile_in_zip_read_info->rest_read_uncompressed) - pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - } - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if (pfile_in_zip_read_info->stream.avail_in == 0) - { - uInt bytes_to_read = UNZ_BUFSIZE; - uInt bytes_not_read = 0; - uInt bytes_read = 0; - uInt total_bytes_read = 0; - - if (pfile_in_zip_read_info->stream.next_in != NULL) - bytes_not_read = pfile_in_zip_read_info->read_buffer + UNZ_BUFSIZE - - pfile_in_zip_read_info->stream.next_in; - bytes_to_read -= bytes_not_read; - if (bytes_not_read > 0) - memcpy(pfile_in_zip_read_info->read_buffer, pfile_in_zip_read_info->stream.next_in, bytes_not_read); - if (pfile_in_zip_read_info->rest_read_compressed < bytes_to_read) - bytes_to_read = (uInt)pfile_in_zip_read_info->rest_read_compressed; - - while (total_bytes_read != bytes_to_read) - { - if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET) != 0) - return UNZ_ERRNO; - - bytes_read = ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->read_buffer + bytes_not_read + total_bytes_read, - bytes_to_read - total_bytes_read); - - total_bytes_read += bytes_read; - pfile_in_zip_read_info->pos_in_zipfile += bytes_read; - - if (bytes_read == 0) - { - if (ZERROR64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream)) - return UNZ_ERRNO; - - err = unzGoToNextDisk(file); - if (err != UNZ_OK) - return err; - - pfile_in_zip_read_info->pos_in_zipfile = 0; - pfile_in_zip_read_info->filestream = s->filestream; - } - } - -#ifndef NOUNCRYPT - if ((s->cur_file_info.flag & 1) != 0) - { -#ifdef HAVE_AES - if (s->cur_file_info.compression_method == AES_METHOD) - { - fcrypt_decrypt(pfile_in_zip_read_info->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx); - } - else -#endif - { - uInt i; - for(i = 0; i < total_bytes_read; i++) - pfile_in_zip_read_info->read_buffer[i] = - zdecode(s->keys, s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); - } - } -#endif - - pfile_in_zip_read_info->rest_read_compressed -= total_bytes_read; - pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)bytes_not_read + total_bytes_read; - } - - if ((pfile_in_zip_read_info->compression_method == 0) || (pfile_in_zip_read_info->raw)) - { - uInt copy,i; - - if ((pfile_in_zip_read_info->stream.avail_in == 0) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (read == 0) ? UNZ_EOF : read; - - if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) - copy = pfile_in_zip_read_info->stream.avail_out; - else - copy = pfile_in_zip_read_info->stream.avail_in; - - for (i = 0; i < copy; i++) - *(pfile_in_zip_read_info->stream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + copy; - pfile_in_zip_read_info->rest_read_uncompressed -= copy; - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, copy); - - pfile_in_zip_read_info->stream.avail_in -= copy; - pfile_in_zip_read_info->stream.avail_out -= copy; - pfile_in_zip_read_info->stream.next_out += copy; - pfile_in_zip_read_info->stream.next_in += copy; - pfile_in_zip_read_info->stream.total_out += copy; - read += copy; - } - else if (pfile_in_zip_read_info->compression_method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - uLong total_out_before, total_out_after; - const Bytef *buf_before; - uLong out_bytes; - - pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; - pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; - pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; - pfile_in_zip_read_info->bstream.total_in_hi32 = 0; - pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; - pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; - pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; - pfile_in_zip_read_info->bstream.total_out_hi32 = 0; - - total_out_before = pfile_in_zip_read_info->bstream.total_out_lo32; - buf_before = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; - - err = BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); - - total_out_after = pfile_in_zip_read_info->bstream.total_out_lo32; - out_bytes = total_out_after-total_out_before; - - pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + out_bytes; - pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,buf_before, (uInt)(out_bytes)); - - read += (uInt)(total_out_after - total_out_before); - - pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; - pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; - pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; - pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; - pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; - pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; - - if (err == BZ_STREAM_END) - return (read == 0) ? UNZ_EOF : read; - if (err != BZ_OK) - break; -#endif - } - else - { - ZPOS64_T total_out_before, total_out_after; - const Bytef *buf_before; - ZPOS64_T out_bytes; - int flush=Z_SYNC_FLUSH; - - total_out_before = pfile_in_zip_read_info->stream.total_out; - buf_before = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err = inflate(&pfile_in_zip_read_info->stream,flush); - - if ((err >= 0) && (pfile_in_zip_read_info->stream.msg != NULL)) - err = Z_DATA_ERROR; - - total_out_after = pfile_in_zip_read_info->stream.total_out; - out_bytes = total_out_after-total_out_before; - - pfile_in_zip_read_info->total_out_64 += out_bytes; - pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,buf_before, (uInt)(out_bytes)); - - read += (uInt)(total_out_after - total_out_before); - - if (err == Z_STREAM_END) - return (read == 0) ? UNZ_EOF : read; - if (err != Z_OK) - break; - } - } - - if (err == Z_OK) - return read; - return err; -} - -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - s = (unz64_s*)file; - if (file == NULL) - return 0; /* UNZ_PARAMERROR */ - pfile_in_zip_read_info= s->pfile_in_zip_read; - if (pfile_in_zip_read_info == NULL) - return 0; /* UNZ_PARAMERROR */ - return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; -} - -extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - uInt read_now; - ZPOS64_T size_to_read; - - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - pfile_in_zip_read_info = s->pfile_in_zip_read; - - if (pfile_in_zip_read_info == NULL) - return UNZ_PARAMERROR; - - size_to_read = pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield; - - if (buf == NULL) - return (int)size_to_read; - - if (len > size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now == 0) - return 0; - - if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, - ZLIB_FILEFUNC_SEEK_SET) != 0) - return UNZ_ERRNO; - - if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf, read_now) != read_now) - return UNZ_ERRNO; - - return (int)read_now; -} - -extern int ZEXPORT unzCloseCurrentFile(unzFile file) -{ - int err = UNZ_OK; - - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info == NULL) - return UNZ_PARAMERROR; - -#ifdef HAVE_AES - if (s->cur_file_info.compression_method == AES_METHOD) - { - unsigned char authcode[AES_AUTHCODESIZE]; - unsigned char rauthcode[AES_AUTHCODESIZE]; - - if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) - return UNZ_ERRNO; - - if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE) - err = UNZ_CRCERROR; - if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0) - err = UNZ_CRCERROR; - } - /* AES zip version AE-1 will expect a valid crc as well */ - if ((s->cur_file_info.compression_method != AES_METHOD) || - (s->cur_file_info_internal.aes_version == 0x0001)) -#endif - { - if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && - (!pfile_in_zip_read_info->raw)) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err = UNZ_CRCERROR; - } - } - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) - inflateEnd(&pfile_in_zip_read_info->stream); -#ifdef HAVE_BZIP2 - else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) - BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); -#endif - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read = NULL; - - return err; -} - -extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) -{ - int err = UNZ_OK; - unz64_s* s; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - s->pos_in_central_dir = s->offset_central_dir; - s->num_file = 0; - err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, - filename,filename_size, extrafield,extrafield_size, comment,comment_size); - s->current_file_ok = (err == UNZ_OK); - if ((err == UNZ_OK) && (pfile_info != NULL)) - memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); - return err; -} - -extern int ZEXPORT unzGoToFirstFile(unzFile file) -{ - return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); -} - -extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, - uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) -{ - unz64_s* s; - int err; - - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ - if (s->num_file+1 == s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment; - s->num_file++; - err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, - filename, filename_size, extrafield,extrafield_size, comment,comment_size); - s->current_file_ok = (err == UNZ_OK); - if ((err == UNZ_OK) && (pfile_info != NULL)) - memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); - return err; -} - -extern int ZEXPORT unzGoToNextFile(unzFile file) -{ - return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); -} - -extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) -{ - unz64_s* s; - int err; - unz_file_info64 cur_file_info_saved; - unz_file_info64_internal cur_file_info_internal_saved; - ZPOS64_T num_file_saved; - ZPOS64_T pos_in_central_dir_saved; - char current_filename[UNZ_MAXFILENAMEINZIP+1]; - - if (file == NULL) - return UNZ_PARAMERROR; - if (strlen(filename) >= UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - /* Save the current state */ - num_file_saved = s->num_file; - pos_in_central_dir_saved = s->pos_in_central_dir; - cur_file_info_saved = s->cur_file_info; - cur_file_info_internal_saved = s->cur_file_info_internal; - - err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0); - - while (err == UNZ_OK) - { - if (filename_compare_func != NULL) - err = filename_compare_func(file, current_filename, filename); - else - err = strcmp(current_filename, filename); - if (err == 0) - return UNZ_OK; - err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0); - } - - /* We failed, so restore the state of the 'current file' to where we were. */ - s->num_file = num_file_saved; - s->pos_in_central_dir = pos_in_central_dir_saved; - s->cur_file_info = cur_file_info_saved; - s->cur_file_info_internal = cur_file_info_internal_saved; - return err; -} - -extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) -{ - unz64_file_pos file_pos64; - int err = unzGetFilePos64(file,&file_pos64); - if (err == UNZ_OK) - { - file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; - file_pos->num_of_file = (uLong)file_pos64.num_of_file; - } - return err; -} - -extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) -{ - unz64_file_pos file_pos64; - - if (file_pos == NULL) - return UNZ_PARAMERROR; - file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; - file_pos64.num_of_file = file_pos->num_of_file; - return unzGoToFilePos64(file,&file_pos64); -} - -extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) -{ - unz64_s* s; - - if (file == NULL || file_pos == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - file_pos->pos_in_zip_directory = s->pos_in_central_dir; - file_pos->num_of_file = s->num_file; - - return UNZ_OK; -} - -extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) -{ - unz64_s* s; - int err; - - if (file == NULL || file_pos == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - - /* jump to the right spot */ - s->pos_in_central_dir = file_pos->pos_in_zip_directory; - s->num_file = file_pos->num_of_file; - - /* set the current file */ - err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal,NULL,0,NULL,0,NULL,0); - /* return results */ - s->current_file_ok = (err == UNZ_OK); - return err; -} - -extern uLong ZEXPORT unzGetOffset(unzFile file) -{ - ZPOS64_T offset64; - - if (file == NULL) - return 0; /* UNZ_PARAMERROR; */ - offset64 = unzGetOffset64(file); - return (uLong)offset64; -} - -extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) -{ - unz64_s* s; - - if (file == NULL) - return 0; /* UNZ_PARAMERROR; */ - s = (unz64_s*)file; - if (!s->current_file_ok) - return 0; - if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) - if (s->num_file == s->gi.number_entry) - return 0; - return s->pos_in_central_dir; -} - -extern int ZEXPORT unzSetOffset(unzFile file, uLong pos) -{ - return unzSetOffset64(file, pos); -} - -extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) -{ - unz64_s* s; - int err; - - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - - s->pos_in_central_dir = pos; - s->num_file = s->gi.number_entry; /* hack */ - err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - -extern z_off_t ZEXPORT unztell(unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - if (pfile_in_zip_read_info == NULL) - return UNZ_PARAMERROR; - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - -extern ZPOS64_T ZEXPORT unztell64(unzFile file) -{ - - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file == NULL) - return (ZPOS64_T)-1; - s = (unz64_s*)file; - pfile_in_zip_read_info = s->pfile_in_zip_read; - - if (pfile_in_zip_read_info == NULL) - return (ZPOS64_T)-1; - - return pfile_in_zip_read_info->total_out_64; -} - -extern int ZEXPORT unzeof(unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file == NULL) - return UNZ_PARAMERROR; - s = (unz64_s*)file; - pfile_in_zip_read_info = s->pfile_in_zip_read; - - if (pfile_in_zip_read_info == NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - return 0; -} +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + Modifications for AES, PKWARE disk spanning + Copyright (C) 2010-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include +#include +#include + +/*#ifndef NOUNCRYPT +# define NOUNCRYPT +#endif*/ + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifdef HAVE_AES +# define AES_METHOD (99) +# define AES_PWVERIFYSIZE (2) +# define AES_MAXSALTLENGTH (16) +# define AES_AUTHCODESIZE (10) +# define AES_HEADERSIZE (11) +# define AES_KEYSIZE(mode) (64 + (mode * 64)) + +# include "aes/aes.h" +# include "aes/fileenc.h" +#endif +#ifndef NOUNCRYPT +# include "crypt.h" +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define DISKHEADERMAGIC (0x08074b50) +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x06064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ +#define SIZEZIPLOCALHEADER (0x1e) + +#ifndef BUFREADCOMMENT +# define BUFREADCOMMENT (0x400) +#endif + +#ifndef UNZ_BUFSIZE +# define UNZ_BUFSIZE (64 * 1024) +#endif +#ifndef UNZ_MAXFILENAMEINZIP +# define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile; /* relative offset of local header 8 bytes */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ +#ifdef HAVE_AES + uLong aes_encryption_mode; + uLong aes_compression_method; + uLong aes_version; +#endif +} unz_file_info64_internal; + +/* file_in_zip_read_info_s contain internal information about a file in zipfile */ +typedef struct +{ + Bytef *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif +#ifdef HAVE_AES + fcrypt_ctx aes_ctx; +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek */ + uLong stream_initialised; /* flag set if stream structure is initialised */ + + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read */ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed; /* number of byte to be obtained after decomp */ + + zlib_filefunc64_32_def z_filefunc; + + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */ + int raw; +} file_in_zip64_read_info_s; + +/* unz64_s contain internal information about the zipfile */ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structure of the current zipfile */ + voidpf filestream_with_CD; /* io structure of the disk with the central directory */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + uLong number_disk; /* number of the current disk, used for spanning ZIP*/ + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; + /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; + /* structure about the current file if we are decompressing it */ + int isZip64; /* is the current file zip64 */ +#ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +#endif +} unz64_s; + +/* Translate date/time from Dos format to tm_unz (readable more easily) */ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate = (ZPOS64_T)(ulDosDate>>16); + + ptm->tm_mday = (uInt)(uDate&0x1f); + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1); + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980); + ptm->tm_hour = (uInt)((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt)((ulDosDate&0x7E0)/0x20); + ptm->tm_sec = (uInt)(2*(ulDosDate&0x1f)); + +#define unz64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) + if (!unz64local_in_range(0, 11, ptm->tm_mon) || + !unz64local_in_range(1, 31, ptm->tm_mday) || + !unz64local_in_range(0, 23, ptm->tm_hour) || + !unz64local_in_range(0, 59, ptm->tm_min) || + !unz64local_in_range(0, 59, ptm->tm_sec)) + /* Invalid date stored, so don't return it. */ + memset(ptm, 0, sizeof(tm_unz)); +#undef unz64local_in_range +} + +/* Read a byte from a gz_stream; Return EOF for end of file. */ +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c, 1); + if (err == 1) + { + *pi = (int)c; + return UNZ_OK; + } + if (ZERROR64(*pzlib_filefunc_def, filestream)) + return UNZ_ERRNO; + return UNZ_EOF; +} + +local int unz64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) +{ + uLong x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i)<<8; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) +{ + uLong x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i)<<8; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((uLong)i)<<16; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i)<<24; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (ZPOS64_T)i; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<8; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<16; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<24; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<32; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<40; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<48; + if (err == UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def, filestream, &i); + x |= ((ZPOS64_T)i)<<56; + + if (err == UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* Locate the Central directory of a zip file (at the end, just before the global comment) */ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T file_size; + ZPOS64_T back_read = 4; + ZPOS64_T max_back = 0xffff; /* maximum size of global comment */ + ZPOS64_T pos_found = 0; + uLong read_size; + ZPOS64_T read_pos; + int i; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT + 4); + if (buf == NULL) + return 0; + + if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) + { + TRYFREE(buf); + return 0; + } + + file_size = ZTELL64(*pzlib_filefunc_def, filestream); + + if (max_back > file_size) + max_back = file_size; + + while (back_read < max_back) + { + if (back_read + BUFREADCOMMENT > max_back) + back_read = max_back; + else + back_read += BUFREADCOMMENT; + + read_pos = file_size - back_read; + read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ? + (BUFREADCOMMENT + 4) : (uLong)(file_size - read_pos); + + if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + break; + if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) + break; + + for (i = (int)read_size-3; (i--) > 0;) + if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) && + ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) && + ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) && + ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff))) + { + pos_found = read_pos+i; + break; + } + + if (pos_found != 0) + break; + } + TRYFREE(buf); + return pos_found; +} + +/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T unz64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + const ZPOS64_T endcentraloffset)); +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + const ZPOS64_T endcentraloffset) +{ + ZPOS64_T offset; + uLong uL; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + + /* read locator signature */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + if (uL != ZIP64ENDLOCHEADERMAGIC) + return 0; + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK) + return 0; + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK) + return 0; + if (uL != ZIP64ENDHEADERMAGIC) + return 0; + + return offset; +} + +local unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + voidpf filestream = NULL; + ZPOS64_T number_entry_CD; + int err = UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.filestream = NULL; + us.filestream_with_CD = NULL; + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def == NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + + us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + + if (us.filestream == NULL) + return NULL; + + us.filestream_with_CD = us.filestream; + us.isZip64 = 0; + + /* Use unz64local_SearchCentralDir first. Only based on the result + is it necessary to locate the unz64local_SearchCentralDir64 */ + central_pos = unz64local_SearchCentralDir(&us.z_filefunc, us.filestream); + if (central_pos) + { + if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.number_disk = uL; + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,& uL) != UNZ_OK) + err = UNZ_ERRNO; + us.gi.number_disk_with_CD = uL; + /* total number of entries in the central directory on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.gi.number_entry = uL; + /* total number of entries in the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + number_entry_CD = uL; + if (number_entry_CD != us.gi.number_entry) + err = UNZ_BADZIPFILE; + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.size_central_dir = uL; + /* offset of start of central directory with respect to the starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + us.offset_central_dir = uL; + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK) + err = UNZ_ERRNO; + + if ((err == UNZ_OK) && + ((us.gi.number_entry == 0xffff) || (us.size_central_dir == 0xffff) || (us.offset_central_dir == 0xffffffff))) + { + /* Format should be Zip64, as the central directory or file size is too large */ + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc, us.filestream, central_pos); + if (central_pos) + { + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &uL64) != UNZ_OK) + err = UNZ_ERRNO; + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK) + err = UNZ_ERRNO; + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK) + err = UNZ_ERRNO; + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK) + err = UNZ_ERRNO; + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK) + err = UNZ_ERRNO; + if (number_entry_CD != us.gi.number_entry) + err = UNZ_BADZIPFILE; + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK) + err = UNZ_ERRNO; + /* offset of start of central directory with respect to the starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK) + err = UNZ_ERRNO; + } + else + err = UNZ_BADZIPFILE; + } + } + else + err = UNZ_ERRNO; + + if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir)) + err = UNZ_BADZIPFILE; + + if (err != UNZ_OK) + { + ZCLOSE64(us.z_filefunc, us.filestream); + return NULL; + } + + if (us.gi.number_disk_with_CD == 0) + { + /* If there is only one disk open another stream so we don't have to seek between the CD + and the file headers constantly */ + filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + if (filestream != NULL) + us.filestream = filestream; + } + + /* Hack for zip files that have no respect for zip64 + if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff)) + us.offset_central_dir = central_pos - us.size_central_dir;*/ + + us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + + s = (unz64_s*)ALLOC(sizeof(unz64_s)); + if (s != NULL) + { + *s = us; + unzGoToFirstFile((unzFile)s); + } + return (unzFile)s; +} + +extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def); + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); + } + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return unzOpenInternal(path, &zlib_filefunc64_32_def_fill); + } + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen(const char *path) +{ + return unzOpenInternal(path, NULL); +} + +extern unzFile ZEXPORT unzOpen64(const void *path) +{ + return unzOpenInternal(path, NULL); +} + +extern int ZEXPORT unzClose(unzFile file) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) + ZCLOSE64(s->z_filefunc, s->filestream); + if (s->filestream_with_CD != NULL) + ZCLOSE64(s->z_filefunc, s->filestream_with_CD); + + s->filestream = NULL; + s->filestream_with_CD = NULL; + TRYFREE(s); + return UNZ_OK; +} + +/* Goto to the next available disk for spanned archives */ +local int unzGoToNextDisk OF((unzFile file)); +local int unzGoToNextDisk(unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uLong number_disk_next = 0; + + s = (unz64_s*)file; + if (s == NULL) + return UNZ_PARAMERROR; + pfile_in_zip_read_info = s->pfile_in_zip_read; + number_disk_next = s->number_disk; + + if ((pfile_in_zip_read_info != NULL) && (pfile_in_zip_read_info->rest_read_uncompressed > 0)) + /* We are currently reading a file and we need the next sequential disk */ + number_disk_next += 1; + else + /* Goto the disk for the current file */ + number_disk_next = s->cur_file_info.disk_num_start; + + if (number_disk_next != s->number_disk) + { + /* Switch disks */ + if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD)) + ZCLOSE64(s->z_filefunc, s->filestream); + + if (number_disk_next == s->gi.number_disk_with_CD) + { + s->filestream = s->filestream_with_CD; + } + else + { + s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next, + ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); + } + + if (s->filestream == NULL) + return UNZ_ERRNO; + + s->number_disk = number_disk_next; + } + + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + *pglobal_info = s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uLong comment_size) +{ + unz64_s* s; + uLong bytes_to_read = comment_size; + if (file == NULL) + return (int)UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (bytes_to_read > s->gi.size_comment) + bytes_to_read = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_ERRNO; + + if (bytes_to_read>0) + { + *comment = 0; + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read) + return UNZ_ERRNO; + } + + if ((comment != NULL) && (comment_size > s->gi.size_comment)) + *(comment+s->gi.size_comment) = 0; + return (int)bytes_to_read; +} + +/* Get Info about the current file in the zipfile, with internal only info */ +local int unz64local_GetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info, + unz_file_info64_internal *pfile_info_internal, char *filename, uLong filename_size, void *extrafield, + uLong extrafield_size, char *comment, uLong comment_size) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + ZPOS64_T bytes_to_read; + int err = UNZ_OK; + uLong uMagic; + long lSeek = 0; + ZPOS64_T current_pos = 0; + uLong acc = 0; + uLong uL; + ZPOS64_T uL64; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, + s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + /* Check the magic */ + if (err == UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != CENTRALHEADERMAGIC) + err = UNZ_BADZIPFILE; + } + + /* Read central directory header */ + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.dosDate) != UNZ_OK) + err = UNZ_ERRNO; + unz64local_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info.compressed_size = uL; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info.uncompressed_size = uL; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK) + err = UNZ_ERRNO; + /* Relative offset of local header */ + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + + file_info.size_file_extra_internal = 0; + file_info.disk_offset = uL; + file_info_internal.offset_curfile = uL; +#ifdef HAVE_AES + file_info_internal.aes_compression_method = 0; + file_info_internal.aes_encryption_mode = 0; + file_info_internal.aes_version = 0; +#endif + + lSeek += file_info.size_filename; + + if ((err == UNZ_OK) && (filename != NULL)) + { + if (file_info.size_filename < filename_size) + { + *(filename+file_info.size_filename) = 0; + bytes_to_read = file_info.size_filename; + } + else + bytes_to_read = filename_size; + + if ((file_info.size_filename > 0) && (filename_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD,filename, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek -= (uLong)bytes_to_read; + } + + /* Read extrafield */ + if ((err == UNZ_OK) && (extrafield != NULL)) + { + if (file_info.size_file_extra < extrafield_size) + bytes_to_read = file_info.size_file_extra; + else + bytes_to_read = extrafield_size; + + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) + lSeek=0; + else + err = UNZ_ERRNO; + } + + if ((file_info.size_file_extra > 0) && (extrafield_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, extrafield, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek += file_info.size_file_extra - (uLong)bytes_to_read; + } + else + lSeek += file_info.size_file_extra; + + if ((err == UNZ_OK) && (file_info.size_file_extra != 0)) + { + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) == 0) + lSeek=0; + else + err = UNZ_ERRNO; + } + + /* We are going to parse the extra field so we need to move back */ + current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD); + if (current_pos < file_info.size_file_extra) + err = UNZ_ERRNO; + current_pos -= file_info.size_file_extra; + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = UNZ_ERRNO; + + while((err != UNZ_ERRNO) && (acc < file_info.size_file_extra)) + { + uLong headerid; + uLong datasize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &headerid) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &datasize) != UNZ_OK) + err = UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerid == 0x0001) + { + /* Subtract size of ZIP64 field, since ZIP64 is handled internally */ + file_info.size_file_extra_internal += 2 + 2 + datasize; + + if (file_info.uncompressed_size == 0xffffffff) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK) + err = UNZ_ERRNO; + } + if (file_info.compressed_size == 0xffffffff) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK) + err = UNZ_ERRNO; + } + if (file_info_internal.offset_curfile == 0xffffffff) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream_with_CD, &uL64) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.offset_curfile = uL64; + file_info.disk_offset = uL64; + } + if (file_info.disk_num_start == 0xffffffff) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK) + err = UNZ_ERRNO; + } + } +#ifdef HAVE_AES + /* AES header */ + else if (headerid == 0x9901) + { + /* Subtract size of AES field, since AES is handled internally */ + file_info.size_file_extra_internal += 2 + 2 + datasize; + + /* Verify version info */ + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + /* Support AE-1 and AE-2 */ + if (uL != 1 && uL != 2) + err = UNZ_ERRNO; + file_info_internal.aes_version = uL; + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if ((char)uL != 'A') + err = UNZ_ERRNO; + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if ((char)uL != 'E') + err = UNZ_ERRNO; + /* Get AES encryption strength and actual compression method */ + if (unz64local_getByte(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.aes_encryption_mode = uL; + if (unz64local_getShort(&s->z_filefunc, s->filestream_with_CD, &uL) != UNZ_OK) + err = UNZ_ERRNO; + file_info_internal.aes_compression_method = uL; + } +#endif + else + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,datasize, ZLIB_FILEFUNC_SEEK_CUR) != 0) + err = UNZ_ERRNO; + } + + acc += 2 + 2 + datasize; + } + } + + if (file_info.disk_num_start == s->gi.number_disk_with_CD) + file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile; + else + file_info_internal.byte_before_the_zipfile = 0; + + if ((err == UNZ_OK) && (comment != NULL)) + { + if (file_info.size_file_comment < comment_size) + { + *(comment+file_info.size_file_comment) = 0; + bytes_to_read = file_info.size_file_comment; + } + else + bytes_to_read = comment_size; + + if (lSeek != 0) + { + if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, lSeek, ZLIB_FILEFUNC_SEEK_CUR) != 0) + err = UNZ_ERRNO; + } + + if ((file_info.size_file_comment > 0) && (comment_size > 0)) + if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, (uLong)bytes_to_read) != bytes_to_read) + err = UNZ_ERRNO; + lSeek += file_info.size_file_comment - (uLong)bytes_to_read; + } + else + lSeek += file_info.size_file_comment; + + if ((err == UNZ_OK) && (pfile_info != NULL)) + *pfile_info = file_info; + + if ((err == UNZ_OK) && (pfile_info_internal != NULL)) + *pfile_info_internal = file_info_internal; + + return err; +} + +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info * pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size) +{ + unz_file_info64 file_info64; + int err; + + err = unz64local_GetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size, + extrafield, extrafield_size, comment, comment_size); + + if ((err == UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} + +extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char* comment, uLong comment_size) +{ + return unz64local_GetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size, + extrafield, extrafield_size, comment,comment_size); +} + +/* Read the local header of the current zipfile. Check the coherency of the local header and info in the + end of central directory about this file store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) */ +local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, ZPOS64_T *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic, uL, uFlags; + uLong size_filename; + uLong size_extra_field; + int err = UNZ_OK; + int compression_method = 0; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + err = unzGoToNextDisk((unzFile)s); + if (err != UNZ_OK) + return err; + + if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile + + s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_ERRNO; + + if (err == UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uMagic) != UNZ_OK) + err = UNZ_ERRNO; + else if (uMagic != LOCALHEADERMAGIC) + err = UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uFlags) != UNZ_OK) + err = UNZ_ERRNO; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uL != s->cur_file_info.compression_method)) + err = UNZ_BADZIPFILE; + + compression_method = (int)s->cur_file_info.compression_method; +#ifdef HAVE_AES + if (compression_method == AES_METHOD) + compression_method = (int)s->cur_file_info_internal.aes_compression_method; +#endif + + if ((err == UNZ_OK) && (compression_method != 0) && +#ifdef HAVE_BZIP2 + (compression_method != Z_BZIP2ED) && +#endif + (compression_method != Z_DEFLATED)) + err = UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* date/time */ + err = UNZ_ERRNO; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* crc */ + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (uL != s->cur_file_info.crc) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size compr */ + err = UNZ_ERRNO; + else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getLong(&s->z_filefunc, s->filestream, &uL) != UNZ_OK) /* size uncompr */ + err = UNZ_ERRNO; + else if ((uL != 0xffffffff) && (err == UNZ_OK) && (uL != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) + err = UNZ_BADZIPFILE; + if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK) + err = UNZ_ERRNO; + else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) + err = UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK) + err = UNZ_ERRNO; + *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password) +{ + int err = UNZ_OK; + int compression_method; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; + uInt size_local_extrafield; +#ifndef NOUNCRYPT + char source[12]; +#else + if (password != NULL) + return UNZ_PARAMERROR; +#endif + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info == NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer = (Bytef*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield = 0; + pfile_in_zip_read_info->raw = raw; + + if (pfile_in_zip_read_info->read_buffer == NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised = 0; + + compression_method = (int)s->cur_file_info.compression_method; +#ifdef HAVE_AES + if (compression_method == AES_METHOD) + compression_method = (int)s->cur_file_info_internal.aes_compression_method; +#endif + + if (method != NULL) + *method = compression_method; + + if (level != NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((compression_method != 0) && +#ifdef HAVE_BZIP2 + (compression_method != Z_BZIP2ED) && +#endif + (compression_method != Z_DEFLATED)) + err = UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; + pfile_in_zip_read_info->crc32 = 0; + pfile_in_zip_read_info->total_out_64 = 0; + pfile_in_zip_read_info->compression_method = compression_method; + pfile_in_zip_read_info->filestream = s->filestream; + pfile_in_zip_read_info->z_filefunc = s->z_filefunc; + if (s->number_disk == s->gi.number_disk_with_CD) + pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; + else + pfile_in_zip_read_info->byte_before_the_zipfile = 0; + pfile_in_zip_read_info->stream.total_out = 0; + pfile_in_zip_read_info->stream.total_in = 0; + pfile_in_zip_read_info->stream.next_in = NULL; + + if (!raw) + { + if (compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if (compression_method == Z_DEFLATED) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)s; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised = Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + } + + pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; + pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; + pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +#ifndef NOUNCRYPT + if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0)) + { + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_INTERNALERROR; +#ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + unsigned char passverify[AES_PWVERIFYSIZE]; + unsigned char saltvalue[AES_MAXSALTLENGTH]; + uInt saltlength; + + if ((s->cur_file_info_internal.aes_encryption_mode < 1) || + (s->cur_file_info_internal.aes_encryption_mode > 3)) + return UNZ_INTERNALERROR; + + saltlength = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode); + + if (ZREAD64(s->z_filefunc, s->filestream, saltvalue, saltlength) != saltlength) + return UNZ_INTERNALERROR; + if (ZREAD64(s->z_filefunc, s->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) + return UNZ_INTERNALERROR; + + fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, password, strlen(password), saltvalue, + passverify, &s->pfile_in_zip_read->aes_ctx); + + pfile_in_zip_read_info->rest_read_compressed -= saltlength + AES_PWVERIFYSIZE; + pfile_in_zip_read_info->rest_read_compressed -= AES_AUTHCODESIZE; + + s->pfile_in_zip_read->pos_in_zipfile += saltlength + AES_PWVERIFYSIZE; + } + else +#endif + { + int i; + s->pcrc_32_tab = (const unsigned long*)get_crc_table(); + init_keys(password, s->keys, s->pcrc_32_tab); + + if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12) + return UNZ_INTERNALERROR; + + for (i = 0; i < 12; i++) + zdecode(s->keys, s->pcrc_32_tab, source[i]); + + pfile_in_zip_read_info->rest_read_compressed -= 12; + + s->pfile_in_zip_read->pos_in_zipfile += 12; + } + } +#endif + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile(unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if some bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ +extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) +{ + int err = UNZ_OK; + uInt read = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len == 0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (pfile_in_zip_read_info->raw) + { + if (len > pfile_in_zip_read_info->rest_read_compressed + pfile_in_zip_read_info->stream.avail_in) + pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed + + pfile_in_zip_read_info->stream.avail_in; + } + else + { + if (len > pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + } + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if (pfile_in_zip_read_info->stream.avail_in == 0) + { + uInt bytes_to_read = UNZ_BUFSIZE; + uInt bytes_not_read = 0; + uInt bytes_read = 0; + uInt total_bytes_read = 0; + + if (pfile_in_zip_read_info->stream.next_in != NULL) + bytes_not_read = pfile_in_zip_read_info->read_buffer + UNZ_BUFSIZE - + pfile_in_zip_read_info->stream.next_in; + bytes_to_read -= bytes_not_read; + if (bytes_not_read > 0) + memcpy(pfile_in_zip_read_info->read_buffer, pfile_in_zip_read_info->stream.next_in, bytes_not_read); + if (pfile_in_zip_read_info->rest_read_compressed < bytes_to_read) + bytes_to_read = (uInt)pfile_in_zip_read_info->rest_read_compressed; + + while (total_bytes_read != bytes_to_read) + { + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_ERRNO; + + bytes_read = ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer + bytes_not_read + total_bytes_read, + bytes_to_read - total_bytes_read); + + total_bytes_read += bytes_read; + pfile_in_zip_read_info->pos_in_zipfile += bytes_read; + + if (bytes_read == 0) + { + if (ZERROR64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream)) + return UNZ_ERRNO; + + err = unzGoToNextDisk(file); + if (err != UNZ_OK) + return err; + + pfile_in_zip_read_info->pos_in_zipfile = 0; + pfile_in_zip_read_info->filestream = s->filestream; + } + } + +#ifndef NOUNCRYPT + if ((s->cur_file_info.flag & 1) != 0) + { +#ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + fcrypt_decrypt(pfile_in_zip_read_info->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx); + } + else +#endif + { + uInt i; + for(i = 0; i < total_bytes_read; i++) + pfile_in_zip_read_info->read_buffer[i] = + zdecode(s->keys, s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); + } + } +#endif + + pfile_in_zip_read_info->rest_read_compressed -= total_bytes_read; + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)bytes_not_read + total_bytes_read; + } + + if ((pfile_in_zip_read_info->compression_method == 0) || (pfile_in_zip_read_info->raw)) + { + uInt copy,i; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (read == 0) ? UNZ_EOF : read; + + if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) + copy = pfile_in_zip_read_info->stream.avail_out; + else + copy = pfile_in_zip_read_info->stream.avail_in; + + for (i = 0; i < copy; i++) + *(pfile_in_zip_read_info->stream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + copy; + pfile_in_zip_read_info->rest_read_uncompressed -= copy; + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, copy); + + pfile_in_zip_read_info->stream.avail_in -= copy; + pfile_in_zip_read_info->stream.avail_out -= copy; + pfile_in_zip_read_info->stream.next_out += copy; + pfile_in_zip_read_info->stream.next_in += copy; + pfile_in_zip_read_info->stream.total_out += copy; + read += copy; + } + else if (pfile_in_zip_read_info->compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong total_out_before, total_out_after; + const Bytef *buf_before; + uLong out_bytes; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + total_out_before = pfile_in_zip_read_info->bstream.total_out_lo32; + buf_before = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err = BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + total_out_after = pfile_in_zip_read_info->bstream.total_out_lo32; + out_bytes = total_out_after-total_out_before; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + out_bytes; + pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,buf_before, (uInt)(out_bytes)); + + read += (uInt)(total_out_after - total_out_before); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err == BZ_STREAM_END) + return (read == 0) ? UNZ_EOF : read; + if (err != BZ_OK) + break; +#endif + } + else + { + ZPOS64_T total_out_before, total_out_after; + const Bytef *buf_before; + ZPOS64_T out_bytes; + int flush=Z_SYNC_FLUSH; + + total_out_before = pfile_in_zip_read_info->stream.total_out; + buf_before = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err = inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err >= 0) && (pfile_in_zip_read_info->stream.msg != NULL)) + err = Z_DATA_ERROR; + + total_out_after = pfile_in_zip_read_info->stream.total_out; + out_bytes = total_out_after-total_out_before; + + pfile_in_zip_read_info->total_out_64 += out_bytes; + pfile_in_zip_read_info->rest_read_uncompressed -= out_bytes; + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,buf_before, (uInt)(out_bytes)); + + read += (uInt)(total_out_after - total_out_before); + + if (err == Z_STREAM_END) + return (read == 0) ? UNZ_EOF : read; + if (err != Z_OK) + break; + } + } + + if (err == Z_OK) + return read; + return err; +} + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s = (unz64_s*)file; + if (file == NULL) + return 0; /* UNZ_PARAMERROR */ + pfile_in_zip_read_info= s->pfile_in_zip_read; + if (pfile_in_zip_read_info == NULL) + return 0; /* UNZ_PARAMERROR */ + return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + + size_to_read = pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield; + + if (buf == NULL) + return (int)size_to_read; + + if (len > size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now == 0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET) != 0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf, read_now) != read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +extern int ZEXPORT unzCloseCurrentFile(unzFile file) +{ + int err = UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + +#ifdef HAVE_AES + if (s->cur_file_info.compression_method == AES_METHOD) + { + unsigned char authcode[AES_AUTHCODESIZE]; + unsigned char rauthcode[AES_AUTHCODESIZE]; + + if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) + return UNZ_ERRNO; + + if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE) + err = UNZ_CRCERROR; + if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0) + err = UNZ_CRCERROR; + } + /* AES zip version AE-1 will expect a valid crc as well */ + if ((s->cur_file_info.compression_method != AES_METHOD) || + (s->cur_file_info_internal.aes_version == 0x0001)) +#endif + { + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err = UNZ_CRCERROR; + } + } + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read = NULL; + + return err; +} + +extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) +{ + int err = UNZ_OK; + unz64_s* s; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + s->pos_in_central_dir = s->offset_central_dir; + s->num_file = 0; + err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, + filename,filename_size, extrafield,extrafield_size, comment,comment_size); + s->current_file_ok = (err == UNZ_OK); + if ((err == UNZ_OK) && (pfile_info != NULL)) + memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); + return err; +} + +extern int ZEXPORT unzGoToFirstFile(unzFile file) +{ + return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); +} + +extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename, + uLong filename_size, void *extrafield, uLong extrafield_size, char *comment, uLong comment_size) +{ + unz64_s* s; + int err; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1 == s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, + filename, filename_size, extrafield,extrafield_size, comment,comment_size); + s->current_file_ok = (err == UNZ_OK); + if ((err == UNZ_OK) && (pfile_info != NULL)) + memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64)); + return err; +} + +extern int ZEXPORT unzGoToNextFile(unzFile file) +{ + return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0); +} + +extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) +{ + unz64_s* s; + int err; + unz_file_info64 cur_file_info_saved; + unz_file_info64_internal cur_file_info_internal_saved; + ZPOS64_T num_file_saved; + ZPOS64_T pos_in_central_dir_saved; + char current_filename[UNZ_MAXFILENAMEINZIP+1]; + + if (file == NULL) + return UNZ_PARAMERROR; + if (strlen(filename) >= UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_file_saved = s->num_file; + pos_in_central_dir_saved = s->pos_in_central_dir; + cur_file_info_saved = s->cur_file_info; + cur_file_info_internal_saved = s->cur_file_info_internal; + + err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0); + + while (err == UNZ_OK) + { + if (filename_compare_func != NULL) + err = filename_compare_func(file, current_filename, filename); + else + err = strcmp(current_filename, filename); + if (err == 0) + return UNZ_OK; + err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0); + } + + /* We failed, so restore the state of the 'current file' to where we were. */ + s->num_file = num_file_saved; + s->pos_in_central_dir = pos_in_central_dir_saved; + s->cur_file_info = cur_file_info_saved; + s->cur_file_info_internal = cur_file_info_internal_saved; + return err; +} + +extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err == UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + + if (file_pos == NULL) + return UNZ_PARAMERROR; + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file == NULL || file_pos == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal,NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern uLong ZEXPORT unzGetOffset(unzFile file) +{ + ZPOS64_T offset64; + + if (file == NULL) + return 0; /* UNZ_PARAMERROR; */ + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file == NULL) + return 0; /* UNZ_PARAMERROR; */ + s = (unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file == s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset(unzFile file, uLong pos) +{ + return unzSetOffset64(file, pos); +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern z_off_t ZEXPORT unztell(unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64(unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return (ZPOS64_T)-1; + s = (unz64_s*)file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + +extern int ZEXPORT unzeof(unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file == NULL) + return UNZ_PARAMERROR; + s = (unz64_s*)file; + pfile_in_zip_read_info = s->pfile_in_zip_read; + + if (pfile_in_zip_read_info == NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + return 0; +} diff --git a/libs/minizip/source/unzipper.cpp b/libs/minizip/source/unzipper.cpp index 9b2fa380..b9a2d3b5 100644 --- a/libs/minizip/source/unzipper.cpp +++ b/libs/minizip/source/unzipper.cpp @@ -1,562 +1,562 @@ -#include "unzipper.h" -#include "defs.h" -#include "tools.h" - -#include -#include -#include -#include - -namespace zipper { - - struct Unzipper::Impl - { - Unzipper& m_outer; - zipFile m_zf; - ourmemory_t m_zipmem; - zlib_filefunc_def m_filefunc; - - private: - - bool initMemory(zlib_filefunc_def& filefunc) - { - m_zf = unzOpen2("__notused__", &filefunc); - return m_zf != NULL; - } - - bool locateEntry(const std::string& name) - { - return UNZ_OK == unzLocateFile(m_zf, name.c_str(), NULL); - } - - ZipEntry currentEntryInfo() - { - unz_file_info64 file_info = { 0 }; - char filename_inzip[256] = { 0 }; - - int err = unzGetCurrentFileInfo64(m_zf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); - if (UNZ_OK != err) - throw EXCEPTION_CLASS("Error, couln't get the current entry info"); - - return ZipEntry(std::string(filename_inzip), file_info.compressed_size, file_info.uncompressed_size, - file_info.tmu_date.tm_year, file_info.tmu_date.tm_mon, file_info.tmu_date.tm_mday, - file_info.tmu_date.tm_hour, file_info.tmu_date.tm_min, file_info.tmu_date.tm_sec, file_info.dosDate); - } - -#if 0 - // lambda as a parameter https://en.wikipedia.org/wiki/C%2B%2B11#Polymorphic_wrappers_for_function_objects - void iterEntries(std::function callback) - { - int err = unzGoToFirstFile(m_zf); - if (UNZ_OK == err) - { - do - { - ZipEntry entryinfo = currentEntryInfo(); - - if (entryinfo.valid()) - { - callback(entryinfo); - err = unzGoToNextFile(m_zf); - } - else - err = UNZ_ERRNO; - - } while (UNZ_OK == err); - - if (UNZ_END_OF_LIST_OF_FILE != err && UNZ_OK != err) - return; - } - } -#endif - - void getEntries(std::vector& entries) - { - int err = unzGoToFirstFile(m_zf); - if (UNZ_OK == err) - { - do - { - ZipEntry entryinfo = currentEntryInfo(); - - if (entryinfo.valid()) - { - entries.push_back(entryinfo); - err = unzGoToNextFile(m_zf); - } - else - err = UNZ_ERRNO; - - } while (UNZ_OK == err); - - if (UNZ_END_OF_LIST_OF_FILE != err && UNZ_OK != err) - return; - } - } - - - public: -#if 0 - bool extractCurrentEntry(ZipEntry& entryinfo, int (extractStrategy)(ZipEntry&) ) - { - int err = UNZ_OK; - - if (!entryinfo.valid()) - return false; - - err = extractStrategy(entryinfo); - if (UNZ_OK == err) - { - err = unzCloseCurrentFile(m_zf); - if (UNZ_OK != err) - throw EXCEPTION_CLASS(("Error " + std::to_string(err) + " closing internal file '" + entryinfo.name + - "' in zip").c_str()); - } - - return UNZ_OK == err; - } -#endif - - bool extractCurrentEntryToFile(ZipEntry& entryinfo, const std::string& fileName) - { - int err = UNZ_OK; - - if (!entryinfo.valid()) - return false; - - err = extractToFile(fileName, entryinfo); - if (UNZ_OK == err) - { - err = unzCloseCurrentFile(m_zf); - if (UNZ_OK != err) - { - std::stringstream str; - str << "Error " << err << " openinginternal file '" - << entryinfo.name << "' in zip"; - - throw EXCEPTION_CLASS(str.str().c_str()); - } - } - - return UNZ_OK == err; - } - - bool extractCurrentEntryToStream(ZipEntry& entryinfo, std::ostream& stream) - { - int err = UNZ_OK; - - if (!entryinfo.valid()) - return false; - - err = extractToStream(stream, entryinfo); - if (UNZ_OK == err) - { - err = unzCloseCurrentFile(m_zf); - if (UNZ_OK != err) - { - std::stringstream str; - str << "Error " << err << " opening internal file '" - << entryinfo.name << "' in zip"; - - throw EXCEPTION_CLASS(str.str().c_str()); - } - } - - return UNZ_OK == err; - } - - bool extractCurrentEntryToMemory(ZipEntry& entryinfo, std::vector& outvec) - { - int err = UNZ_OK; - - if (!entryinfo.valid()) - return false; - - err = extractToMemory(outvec, entryinfo); - if (UNZ_OK == err) - { - err = unzCloseCurrentFile(m_zf); - if (UNZ_OK != err) - { - std::stringstream str; - str << "Error " << err << " opening internal file '" - << entryinfo.name << "' in zip"; - - throw EXCEPTION_CLASS(str.str().c_str()); - } - } - - return UNZ_OK == err; - } - - void changeFileDate(const std::string& filename, uLong dosdate, tm_unz tmu_date) - { -#ifdef _WIN32 - HANDLE hFile; - FILETIME ftm, ftLocal, ftCreate, ftLastAcc, ftLastWrite; - - hFile = CreateFileA(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite); - DosDateTimeToFileTime((WORD)(dosdate >> 16), (WORD)dosdate, &ftLocal); - LocalFileTimeToFileTime(&ftLocal, &ftm); - SetFileTime(hFile, &ftm, &ftLastAcc, &ftm); - CloseHandle(hFile); - } -#else -#if defined unix || defined __APPLE__ - struct utimbuf ut; - struct tm newdate; - - newdate.tm_sec = tmu_date.tm_sec; - newdate.tm_min = tmu_date.tm_min; - newdate.tm_hour = tmu_date.tm_hour; - newdate.tm_mday = tmu_date.tm_mday; - newdate.tm_mon = tmu_date.tm_mon; - if (tmu_date.tm_year > 1900) - newdate.tm_year = tmu_date.tm_year - 1900; - else - newdate.tm_year = tmu_date.tm_year; - newdate.tm_isdst = -1; - - ut.actime = ut.modtime = mktime(&newdate); - utime(filename.c_str(), &ut); -#endif -#endif - } - - - int extractToFile(const std::string& filename, ZipEntry& info) - { - int err = UNZ_ERRNO; - - /* If zip entry is a directory then create it on disk */ - makedir(parentDirectory(filename)); - - /* Create the file on disk so we can unzip to it */ - std::ofstream output_file(filename.c_str(), std::ofstream::binary); - - if (output_file.good()) - { - if (extractToStream(output_file, info)) - err = UNZ_OK; - - output_file.close(); - - /* Set the time of the file that has been unzipped */ - tm_unz timeaux; - memcpy(&timeaux, &info.unixdate, sizeof(timeaux)); - - changeFileDate(filename, info.dosdate, timeaux); - } - else - output_file.close(); - - return err; - } - - int extractToStream(std::ostream& stream, ZipEntry& info) - { - size_t err = UNZ_ERRNO; - - err = unzOpenCurrentFilePassword(m_zf, m_outer.m_password.c_str()); - if (UNZ_OK != err) - { - std::stringstream str; - str << "Error " << err << " opening internal file '" - << info.name << "' in zip"; - - throw EXCEPTION_CLASS(str.str().c_str()); - } - - std::vector buffer; - buffer.resize(WRITEBUFFERSIZE); - - do - { - err = unzReadCurrentFile(m_zf, buffer.data(), (unsigned int)buffer.size()); - if (err < 0 || err == 0) - break; - - stream.write(buffer.data(), err); - if (!stream.good()) - { - err = UNZ_ERRNO; - break; - } - - } while (err > 0); - - stream.flush(); - - return (int)err; - } - - int extractToMemory(std::vector& outvec, ZipEntry& info) - { - size_t err = UNZ_ERRNO; - - err = unzOpenCurrentFilePassword(m_zf, m_outer.m_password.c_str()); - if (UNZ_OK != err) - { - std::stringstream str; - str << "Error " << err << " opening internal file '" - << info.name << "' in zip"; - - throw EXCEPTION_CLASS(str.str().c_str()); - } - - std::vector buffer; - buffer.resize(WRITEBUFFERSIZE); - - outvec.reserve((size_t)info.uncompressedSize); - - do - { - err = unzReadCurrentFile(m_zf, buffer.data(), (unsigned int)buffer.size()); - if (err < 0 || err == 0) - break; - - outvec.insert(outvec.end(), buffer.data(), buffer.data() + err); - - } while (err > 0); - - return (int)err; - } - - public: - - Impl(Unzipper& outer) : m_outer(outer), m_zipmem(), m_filefunc() - { - m_zf = NULL; - } - - ~Impl() - { - } - - void close() - { - if (m_zf) - unzClose(m_zf); - } - - bool initFile(const std::string& filename) - { -#ifdef USEWIN32IOAPI - zlib_filefunc64_def ffunc; - fill_win32_filefunc64A(&ffunc); - m_zf = unzOpen2_64(filename.c_str(), &ffunc); -#else - m_zf = unzOpen64(filename.c_str()); -#endif - return m_zf != NULL; - } - - bool initWithStream(std::istream& stream) - { - stream.seekg(0, std::ios::end); - size_t size = (size_t)stream.tellg(); - stream.seekg(0); - - if (size > 0) - { - m_zipmem.base = new char[(size_t)size]; - stream.read(m_zipmem.base, size); - } - - fill_memory_filefunc(&m_filefunc, &m_zipmem); - - return initMemory(m_filefunc); - } - - bool initWithVector(std::vector& buffer) - { - if (!buffer.empty()) - { - m_zipmem.base = (char*)buffer.data(); - m_zipmem.size = (uLong)buffer.size(); - } - - fill_memory_filefunc(&m_filefunc, &m_zipmem); - - return initMemory(m_filefunc); - } - - std::vector entries() - { - std::vector entrylist; - getEntries(entrylist); - return entrylist; - } - - - - bool extractAll(const std::string& destination, const std::map& alternativeNames) - { - std::vector entries; - getEntries(entries); - std::vector::iterator it = entries.begin(); - for (; it != entries.end(); ++it) - { - if (!locateEntry(it->name)) - continue; - - std::string alternativeName = destination.empty() ? "" : destination + "/"; - - if (alternativeNames.find(it->name) != alternativeNames.end()) - alternativeName += alternativeNames.at(it->name); - else - alternativeName += it->name; - - this->extractCurrentEntryToFile(*it, alternativeName); - }; - - return true; - } - - bool extractEntry(const std::string& name, const std::string& destination) - { - std::string outputFile = destination.empty() ? name : destination + "\\" + name; - - if (locateEntry(name)) - { - ZipEntry entry = currentEntryInfo(); - return extractCurrentEntryToFile(entry, outputFile); - } - else - { - return false; - } - } - - bool extractEntryToStream(const std::string& name, std::ostream& stream) - { - if (locateEntry(name)) - { - ZipEntry entry = currentEntryInfo(); - return extractCurrentEntryToStream(entry, stream); - } - else - { - return false; - } - } - - bool extractEntryToMemory(const std::string& name, std::vector& vec) - { - if (locateEntry(name)) - { - ZipEntry entry = currentEntryInfo(); - return extractCurrentEntryToMemory(entry, vec); - } - else - { - return false; - } - } - }; - - Unzipper::Unzipper(std::istream& zippedBuffer) - : m_ibuffer(zippedBuffer) - , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_usingMemoryVector(false) - , m_usingStream(true) - , m_impl(new Impl(*this)) - { - if (!m_impl->initWithStream(m_ibuffer)) - throw EXCEPTION_CLASS("Error loading zip in memory!"); - m_open = true; - } - - Unzipper::Unzipper(std::vector& zippedBuffer) - : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_vecbuffer(zippedBuffer) - , m_usingMemoryVector(true) - , m_usingStream(false) - , m_impl(new Impl(*this)) - { - if (!m_impl->initWithVector(m_vecbuffer)) - throw EXCEPTION_CLASS("Error loading zip in memory!"); - - m_open = true; - } - - Unzipper::Unzipper(const std::string& zipname) - : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_zipname(zipname) - , m_usingMemoryVector(false) - , m_usingStream(false) - , m_impl(new Impl(*this)) - { - if (!m_impl->initFile(zipname)) - throw EXCEPTION_CLASS("Error loading zip file!"); - - m_open = true; - } - - Unzipper::Unzipper(const std::string& zipname, const std::string& password) - : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_zipname(zipname) - , m_password(password) - , m_usingMemoryVector(false) - , m_usingStream(false) - , m_impl(new Impl(*this)) - { - if (!m_impl->initFile(zipname)) - throw EXCEPTION_CLASS("Error loading zip file!"); - - m_open = true; - } - - Unzipper::~Unzipper(void) - { - close(); - } - - std::vector Unzipper::entries() - { - return m_impl->entries(); - } - - bool Unzipper::extractEntry(const std::string& name, const std::string& destination) - { - return m_impl->extractEntry(name, destination); - } - - bool Unzipper::extractEntryToStream(const std::string& name, std::ostream& stream) - { - return m_impl->extractEntryToStream(name, stream); - } - - bool Unzipper::extractEntryToMemory(const std::string& name, std::vector& vec) - { - return m_impl->extractEntryToMemory(name, vec); - } - - - bool Unzipper::extract(const std::string& destination, const std::map& alternativeNames) - { - return m_impl->extractAll(destination, alternativeNames); - } - - bool - Unzipper::extract(const std::string& destination) - { - return m_impl->extractAll(destination, std::map()); - } - - void Unzipper::close() - { - if (m_open) - { - m_impl->close(); - m_open = false; - } - } - -} - +#include "unzipper.h" +#include "defs.h" +#include "tools.h" + +#include +#include +#include +#include + +namespace zipper { + + struct Unzipper::Impl + { + Unzipper& m_outer; + zipFile m_zf; + ourmemory_t m_zipmem; + zlib_filefunc_def m_filefunc; + + private: + + bool initMemory(zlib_filefunc_def& filefunc) + { + m_zf = unzOpen2("__notused__", &filefunc); + return m_zf != NULL; + } + + bool locateEntry(const std::string& name) + { + return UNZ_OK == unzLocateFile(m_zf, name.c_str(), NULL); + } + + ZipEntry currentEntryInfo() + { + unz_file_info64 file_info = { 0 }; + char filename_inzip[256] = { 0 }; + + int err = unzGetCurrentFileInfo64(m_zf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (UNZ_OK != err) + throw EXCEPTION_CLASS("Error, couln't get the current entry info"); + + return ZipEntry(std::string(filename_inzip), file_info.compressed_size, file_info.uncompressed_size, + file_info.tmu_date.tm_year, file_info.tmu_date.tm_mon, file_info.tmu_date.tm_mday, + file_info.tmu_date.tm_hour, file_info.tmu_date.tm_min, file_info.tmu_date.tm_sec, file_info.dosDate); + } + +#if 0 + // lambda as a parameter https://en.wikipedia.org/wiki/C%2B%2B11#Polymorphic_wrappers_for_function_objects + void iterEntries(std::function callback) + { + int err = unzGoToFirstFile(m_zf); + if (UNZ_OK == err) + { + do + { + ZipEntry entryinfo = currentEntryInfo(); + + if (entryinfo.valid()) + { + callback(entryinfo); + err = unzGoToNextFile(m_zf); + } + else + err = UNZ_ERRNO; + + } while (UNZ_OK == err); + + if (UNZ_END_OF_LIST_OF_FILE != err && UNZ_OK != err) + return; + } + } +#endif + + void getEntries(std::vector& entries) + { + int err = unzGoToFirstFile(m_zf); + if (UNZ_OK == err) + { + do + { + ZipEntry entryinfo = currentEntryInfo(); + + if (entryinfo.valid()) + { + entries.push_back(entryinfo); + err = unzGoToNextFile(m_zf); + } + else + err = UNZ_ERRNO; + + } while (UNZ_OK == err); + + if (UNZ_END_OF_LIST_OF_FILE != err && UNZ_OK != err) + return; + } + } + + + public: +#if 0 + bool extractCurrentEntry(ZipEntry& entryinfo, int (extractStrategy)(ZipEntry&) ) + { + int err = UNZ_OK; + + if (!entryinfo.valid()) + return false; + + err = extractStrategy(entryinfo); + if (UNZ_OK == err) + { + err = unzCloseCurrentFile(m_zf); + if (UNZ_OK != err) + throw EXCEPTION_CLASS(("Error " + std::to_string(err) + " closing internal file '" + entryinfo.name + + "' in zip").c_str()); + } + + return UNZ_OK == err; + } +#endif + + bool extractCurrentEntryToFile(ZipEntry& entryinfo, const std::string& fileName) + { + int err = UNZ_OK; + + if (!entryinfo.valid()) + return false; + + err = extractToFile(fileName, entryinfo); + if (UNZ_OK == err) + { + err = unzCloseCurrentFile(m_zf); + if (UNZ_OK != err) + { + std::stringstream str; + str << "Error " << err << " openinginternal file '" + << entryinfo.name << "' in zip"; + + throw EXCEPTION_CLASS(str.str().c_str()); + } + } + + return UNZ_OK == err; + } + + bool extractCurrentEntryToStream(ZipEntry& entryinfo, std::ostream& stream) + { + int err = UNZ_OK; + + if (!entryinfo.valid()) + return false; + + err = extractToStream(stream, entryinfo); + if (UNZ_OK == err) + { + err = unzCloseCurrentFile(m_zf); + if (UNZ_OK != err) + { + std::stringstream str; + str << "Error " << err << " opening internal file '" + << entryinfo.name << "' in zip"; + + throw EXCEPTION_CLASS(str.str().c_str()); + } + } + + return UNZ_OK == err; + } + + bool extractCurrentEntryToMemory(ZipEntry& entryinfo, std::vector& outvec) + { + int err = UNZ_OK; + + if (!entryinfo.valid()) + return false; + + err = extractToMemory(outvec, entryinfo); + if (UNZ_OK == err) + { + err = unzCloseCurrentFile(m_zf); + if (UNZ_OK != err) + { + std::stringstream str; + str << "Error " << err << " opening internal file '" + << entryinfo.name << "' in zip"; + + throw EXCEPTION_CLASS(str.str().c_str()); + } + } + + return UNZ_OK == err; + } + + void changeFileDate(const std::string& filename, uLong dosdate, tm_unz tmu_date) + { +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm, ftLocal, ftCreate, ftLastAcc, ftLastWrite; + + hFile = CreateFileA(filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate >> 16), (WORD)dosdate, &ftLocal); + LocalFileTimeToFileTime(&ftLocal, &ftm); + SetFileTime(hFile, &ftm, &ftLastAcc, &ftm); + CloseHandle(hFile); + } +#else +#if defined unix || defined __APPLE__ + struct utimbuf ut; + struct tm newdate; + + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min = tmu_date.tm_min; + newdate.tm_hour = tmu_date.tm_hour; + newdate.tm_mday = tmu_date.tm_mday; + newdate.tm_mon = tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year = tmu_date.tm_year - 1900; + else + newdate.tm_year = tmu_date.tm_year; + newdate.tm_isdst = -1; + + ut.actime = ut.modtime = mktime(&newdate); + utime(filename.c_str(), &ut); +#endif +#endif + } + + + int extractToFile(const std::string& filename, ZipEntry& info) + { + int err = UNZ_ERRNO; + + /* If zip entry is a directory then create it on disk */ + makedir(parentDirectory(filename)); + + /* Create the file on disk so we can unzip to it */ + std::ofstream output_file(filename.c_str(), std::ofstream::binary); + + if (output_file.good()) + { + if (extractToStream(output_file, info)) + err = UNZ_OK; + + output_file.close(); + + /* Set the time of the file that has been unzipped */ + tm_unz timeaux; + memcpy(&timeaux, &info.unixdate, sizeof(timeaux)); + + changeFileDate(filename, info.dosdate, timeaux); + } + else + output_file.close(); + + return err; + } + + int extractToStream(std::ostream& stream, ZipEntry& info) + { + size_t err = UNZ_ERRNO; + + err = unzOpenCurrentFilePassword(m_zf, m_outer.m_password.c_str()); + if (UNZ_OK != err) + { + std::stringstream str; + str << "Error " << err << " opening internal file '" + << info.name << "' in zip"; + + throw EXCEPTION_CLASS(str.str().c_str()); + } + + std::vector buffer; + buffer.resize(WRITEBUFFERSIZE); + + do + { + err = unzReadCurrentFile(m_zf, buffer.data(), (unsigned int)buffer.size()); + if (err < 0 || err == 0) + break; + + stream.write(buffer.data(), err); + if (!stream.good()) + { + err = UNZ_ERRNO; + break; + } + + } while (err > 0); + + stream.flush(); + + return (int)err; + } + + int extractToMemory(std::vector& outvec, ZipEntry& info) + { + size_t err = UNZ_ERRNO; + + err = unzOpenCurrentFilePassword(m_zf, m_outer.m_password.c_str()); + if (UNZ_OK != err) + { + std::stringstream str; + str << "Error " << err << " opening internal file '" + << info.name << "' in zip"; + + throw EXCEPTION_CLASS(str.str().c_str()); + } + + std::vector buffer; + buffer.resize(WRITEBUFFERSIZE); + + outvec.reserve((size_t)info.uncompressedSize); + + do + { + err = unzReadCurrentFile(m_zf, buffer.data(), (unsigned int)buffer.size()); + if (err < 0 || err == 0) + break; + + outvec.insert(outvec.end(), buffer.data(), buffer.data() + err); + + } while (err > 0); + + return (int)err; + } + + public: + + Impl(Unzipper& outer) : m_outer(outer), m_zipmem(), m_filefunc() + { + m_zf = NULL; + } + + ~Impl() + { + } + + void close() + { + if (m_zf) + unzClose(m_zf); + } + + bool initFile(const std::string& filename) + { +#ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + m_zf = unzOpen2_64(filename.c_str(), &ffunc); +#else + m_zf = unzOpen64(filename.c_str()); +#endif + return m_zf != NULL; + } + + bool initWithStream(std::istream& stream) + { + stream.seekg(0, std::ios::end); + size_t size = (size_t)stream.tellg(); + stream.seekg(0); + + if (size > 0) + { + m_zipmem.base = new char[(size_t)size]; + stream.read(m_zipmem.base, size); + } + + fill_memory_filefunc(&m_filefunc, &m_zipmem); + + return initMemory(m_filefunc); + } + + bool initWithVector(std::vector& buffer) + { + if (!buffer.empty()) + { + m_zipmem.base = (char*)buffer.data(); + m_zipmem.size = (uLong)buffer.size(); + } + + fill_memory_filefunc(&m_filefunc, &m_zipmem); + + return initMemory(m_filefunc); + } + + std::vector entries() + { + std::vector entrylist; + getEntries(entrylist); + return entrylist; + } + + + + bool extractAll(const std::string& destination, const std::map& alternativeNames) + { + std::vector entries; + getEntries(entries); + std::vector::iterator it = entries.begin(); + for (; it != entries.end(); ++it) + { + if (!locateEntry(it->name)) + continue; + + std::string alternativeName = destination.empty() ? "" : destination + "/"; + + if (alternativeNames.find(it->name) != alternativeNames.end()) + alternativeName += alternativeNames.at(it->name); + else + alternativeName += it->name; + + this->extractCurrentEntryToFile(*it, alternativeName); + }; + + return true; + } + + bool extractEntry(const std::string& name, const std::string& destination) + { + std::string outputFile = destination.empty() ? name : destination + "\\" + name; + + if (locateEntry(name)) + { + ZipEntry entry = currentEntryInfo(); + return extractCurrentEntryToFile(entry, outputFile); + } + else + { + return false; + } + } + + bool extractEntryToStream(const std::string& name, std::ostream& stream) + { + if (locateEntry(name)) + { + ZipEntry entry = currentEntryInfo(); + return extractCurrentEntryToStream(entry, stream); + } + else + { + return false; + } + } + + bool extractEntryToMemory(const std::string& name, std::vector& vec) + { + if (locateEntry(name)) + { + ZipEntry entry = currentEntryInfo(); + return extractCurrentEntryToMemory(entry, vec); + } + else + { + return false; + } + } + }; + + Unzipper::Unzipper(std::istream& zippedBuffer) + : m_ibuffer(zippedBuffer) + , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_usingMemoryVector(false) + , m_usingStream(true) + , m_impl(new Impl(*this)) + { + if (!m_impl->initWithStream(m_ibuffer)) + throw EXCEPTION_CLASS("Error loading zip in memory!"); + m_open = true; + } + + Unzipper::Unzipper(std::vector& zippedBuffer) + : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_vecbuffer(zippedBuffer) + , m_usingMemoryVector(true) + , m_usingStream(false) + , m_impl(new Impl(*this)) + { + if (!m_impl->initWithVector(m_vecbuffer)) + throw EXCEPTION_CLASS("Error loading zip in memory!"); + + m_open = true; + } + + Unzipper::Unzipper(const std::string& zipname) + : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_zipname(zipname) + , m_usingMemoryVector(false) + , m_usingStream(false) + , m_impl(new Impl(*this)) + { + if (!m_impl->initFile(zipname)) + throw EXCEPTION_CLASS("Error loading zip file!"); + + m_open = true; + } + + Unzipper::Unzipper(const std::string& zipname, const std::string& password) + : m_ibuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_zipname(zipname) + , m_password(password) + , m_usingMemoryVector(false) + , m_usingStream(false) + , m_impl(new Impl(*this)) + { + if (!m_impl->initFile(zipname)) + throw EXCEPTION_CLASS("Error loading zip file!"); + + m_open = true; + } + + Unzipper::~Unzipper(void) + { + close(); + } + + std::vector Unzipper::entries() + { + return m_impl->entries(); + } + + bool Unzipper::extractEntry(const std::string& name, const std::string& destination) + { + return m_impl->extractEntry(name, destination); + } + + bool Unzipper::extractEntryToStream(const std::string& name, std::ostream& stream) + { + return m_impl->extractEntryToStream(name, stream); + } + + bool Unzipper::extractEntryToMemory(const std::string& name, std::vector& vec) + { + return m_impl->extractEntryToMemory(name, vec); + } + + + bool Unzipper::extract(const std::string& destination, const std::map& alternativeNames) + { + return m_impl->extractAll(destination, alternativeNames); + } + + bool + Unzipper::extract(const std::string& destination) + { + return m_impl->extractAll(destination, std::map()); + } + + void Unzipper::close() + { + if (m_open) + { + m_impl->close(); + m_open = false; + } + } + +} + diff --git a/libs/minizip/source/zip.c b/libs/minizip/source/zip.c index 5dc146c2..b3fdd723 100644 --- a/libs/minizip/source/zip.c +++ b/libs/minizip/source/zip.c @@ -1,2021 +1,2021 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - - Copyright (C) 1998-2010 Gilles Vollant - http://www.winimage.com/zLibDll/minizip.html - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson - http://result42.com - Modifications for AES, PKWARE disk spanning - Copyright (C) 2010-2014 Nathan Moinvaziri - - This program is distributed under the terms of the same license as zlib. - See the accompanying LICENSE file for the full text of the license. -*/ - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - -#ifdef HAVE_AES -# define AES_METHOD (99) -# define AES_PWVERIFYSIZE (2) -# define AES_AUTHCODESIZE (10) -# define AES_MAXSALTLENGTH (16) -# define AES_VERSION (0x0001) -# define AES_ENCRYPTIONMODE (0x03) - -# include "aes/aes.h" -# include "aes/fileenc.h" -# include "aes/prng.h" -# include "aes/entropy.h" -#endif - -#ifndef NOCRYPT -# define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -# include "crypt.h" -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define DISKHEADERMAGIC (0x08074b50) -#define LOCALHEADERMAGIC (0x04034b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) -#define ZIP64ENDHEADERMAGIC (0x06064b50) -#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ -#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - -#ifndef BUFREADCOMMENT -# define BUFREADCOMMENT (0x400) -#endif -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x0) /* platform dependent */ -#endif - -#ifndef Z_BUFSIZE -# define Z_BUFSIZE (64*1024) -#endif -#ifndef Z_MAXFILENAMEINZIP -# define Z_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -/* NOT sure that this work on ALL platform */ -#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif - -const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - -typedef struct linkedlist_datablock_internal_s -{ - struct linkedlist_datablock_internal_s* next_datablock; - uLong avail_in_this_block; - uLong filled_in_this_block; - uLong unused; /* for future use and alignment */ - unsigned char data[SIZEDATA_INDATABLOCK]; -} linkedlist_datablock_internal; - -typedef struct linkedlist_data_s -{ - linkedlist_datablock_internal* first_block; - linkedlist_datablock_internal* last_block; -} linkedlist_data; - -typedef struct -{ - z_stream stream; /* zLib stream structure for inflate */ -#ifdef HAVE_BZIP2 - bz_stream bstream; /* bzLib stream structure for bziped */ -#endif -#ifdef HAVE_AES - fcrypt_ctx aes_ctx; - prng_ctx aes_rng[1]; -#endif - int stream_initialised; /* 1 is stream is initialized */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - ZPOS64_T pos_local_header; /* offset of the local header of the file currently writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralextra; - uLong size_centralheader; /* size of the central header for cur file */ - uLong size_centralextrafree; /* Extra bytes allocated to the central header but that are not used */ - uLong size_comment; - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method written to file.*/ - int compression_method; /* compression method to use */ - int raw; /* 1 for directly writing raw data */ - Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be writ*/ - uLong dosDate; - uLong crc32; - int zip64; /* Add ZIP64 extended information in the extra field */ - uLong number_disk; /* number of current disk used for spanning ZIP */ - ZPOS64_T pos_zip64extrainfo; - ZPOS64_T total_compressed; - ZPOS64_T total_uncompressed; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile64_info; - -typedef struct -{ - zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structure of the zipfile */ - voidpf filestream_with_CD; /* io structure of the zipfile with the central dir */ - linkedlist_data central_dir; /* datablock with central dir in construction*/ - int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - int append; /* append mode */ - curfile64_info ci; /* info on the file currently writing */ - - ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ - ZPOS64_T add_position_when_writting_offset; - ZPOS64_T number_entry; - ZPOS64_T disk_size; /* size of each disk */ - uLong number_disk; /* number of the current disk, used for spanning ZIP */ - uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif -} zip64_internal; - -/* Allocate a new data block */ -local linkedlist_datablock_internal* allocate_new_datablock OF(()); -local linkedlist_datablock_internal* allocate_new_datablock() -{ - linkedlist_datablock_internal* ldi; - - ldi = (linkedlist_datablock_internal*)ALLOC(sizeof(linkedlist_datablock_internal)); - - if (ldi != NULL) - { - ldi->next_datablock = NULL; - ldi->filled_in_this_block = 0; - ldi->avail_in_this_block = SIZEDATA_INDATABLOCK; - } - return ldi; -} - -/* Free data block in linked list */ -local void free_datablock OF((linkedlist_datablock_internal* ldi)); -local void free_datablock(linkedlist_datablock_internal* ldi) -{ - while (ldi != NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -/* Initialize linked list */ -local void init_linkedlist OF((linkedlist_data* ll)); -local void init_linkedlist(linkedlist_data* ll) -{ - ll->first_block = ll->last_block = NULL; -} - -/* Free entire linked list and all data blocks */ -local void free_linkedlist OF((linkedlist_data* ll)); -local void free_linkedlist(linkedlist_data* ll) -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} - -/* Add data to linked list data block */ -local int add_data_in_datablock OF((linkedlist_data* ll, const void* buf, uLong len)); -local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) -{ - linkedlist_datablock_internal* ldi; - const unsigned char* from_copy; - - if (ll == NULL) - return ZIP_INTERNALERROR; - - if (ll->last_block == NULL) - { - ll->first_block = ll->last_block = allocate_new_datablock(); - if (ll->first_block == NULL) - return ZIP_INTERNALERROR; - } - - ldi = ll->last_block; - from_copy = (unsigned char*)buf; - - while (len>0) - { - uInt copy_this; - uInt i; - unsigned char* to_copy; - - if (ldi->avail_in_this_block == 0) - { - ldi->next_datablock = allocate_new_datablock(); - if (ldi->next_datablock == NULL) - return ZIP_INTERNALERROR; - ldi = ldi->next_datablock ; - ll->last_block = ldi; - } - - if (ldi->avail_in_this_block < len) - copy_this = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - -local uLong zip64local_TmzDateToDosDate OF((const tm_zip* ptm)); -local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) -{ - uLong year; -#define zip64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) - /* Years supported: - * [00, 79] (assumed to be between 2000 and 2079) - * [80, 207] (assumed to be between 1980 and 2107, typical output of old - software that does 'year-1900' to get a double digit year) - * [1980, 2107] - Due to the date format limitations, only years between 1980 and 2107 can be stored. - */ - if (!(zip64local_in_range(1980, 2107, ptm->tm_year) || zip64local_in_range(0, 207, ptm->tm_year)) || - !zip64local_in_range(0, 11, ptm->tm_mon) || - !zip64local_in_range(1, 31, ptm->tm_mday) || - !zip64local_in_range(0, 23, ptm->tm_hour) || - !zip64local_in_range(0, 59, ptm->tm_min) || - !zip64local_in_range(0, 59, ptm->tm_sec)) - return 0; -#undef zip64local_in_range - - year = (uLong)ptm->tm_year; - if (year >= 1980) /* range [1980, 2107] */ - year -= 1980; - else if (year >= 80) /* range [80, 99] */ - year -= 80; - else /* range [00, 79] */ - year += 20; - - return - (uLong)(((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); -} - -/* Inputs a long in LSB order to the given file: nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ -local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - ZPOS64_T x, int nbByte)); -local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - ZPOS64_T x, int nbByte) -{ - unsigned char buf[8]; - int n; - for (n = 0; n < nbByte; n++) - { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - if (x != 0) - { - /* data overflow - hack for ZIP64 (X Roche) */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } - - if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - - return ZIP_OK; -} - -local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); -local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) -{ - unsigned char* buf =(unsigned char*)dest; - int n; - for (n = 0; n < nbByte; n++) { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - - if (x != 0) - { - /* data overflow - hack for ZIP64 */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } -} - -local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); -local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c,1); - if (err == 1) - { - *pi = (int)c; - return ZIP_OK; - } - if (ZERROR64(*pzlib_filefunc_def, filestream)) - return ZIP_ERRNO; - return ZIP_EOF; -} - -local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); -local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (uLong)i; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((uLong)i) << 8; - - if (err == ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); -local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (uLong)i; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((uLong)i)<<8; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((uLong)i)<<16; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((uLong)i)<<24; - - if (err == ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); -local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) -{ - ZPOS64_T x; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x = (ZPOS64_T)i; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<8; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<16; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<24; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<32; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<40; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<48; - if (err == ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); - x += ((ZPOS64_T)i)<<56; - - if (err == ZIP_OK) - *pX = x; - else - *pX = 0; - - return err; -} - -/* Gets the amount of bytes left to write to the current disk for spanning archives */ -local int zipGetDiskSizeAvailable OF((zipFile file, ZPOS64_T *size_available)); -local int zipGetDiskSizeAvailable(zipFile file, ZPOS64_T *size_available) -{ - zip64_internal* zi; - ZPOS64_T current_disk_size; - - zi = (zip64_internal*)file; - ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); - current_disk_size = ZTELL64(zi->z_filefunc, zi->filestream); - *size_available = zi->disk_size - current_disk_size; - return ZIP_OK; -} - -/* Goes to a specific disk number for spanning archives */ -local int zipGoToSpecificDisk OF((zipFile file, int number_disk, int open_existing)); -local int zipGoToSpecificDisk(zipFile file, int number_disk, int open_existing) -{ - zip64_internal* zi; - int err = ZIP_OK; - - zi = (zip64_internal*)file; - if (zi->disk_size == 0) - return err; - - if ((zi->filestream != NULL) && (zi->filestream != zi->filestream_with_CD)) - ZCLOSE64(zi->z_filefunc, zi->filestream); - - zi->filestream = ZOPENDISK64(zi->z_filefunc, zi->filestream_with_CD, number_disk, (open_existing == 1) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE)); - - if (zi->filestream == NULL) - err = ZIP_ERRNO; - - return err; -} - -/* Goes to the first disk in a spanned archive */ -local int zipGoToFirstDisk OF((zipFile file)); -local int zipGoToFirstDisk(zipFile file) -{ - zip64_internal* zi; - int number_disk_next; - int err = ZIP_OK; - - zi = (zip64_internal*)file; - - if (zi->disk_size == 0) - return err; - number_disk_next = 0; - if (zi->number_disk_with_CD > 0) - number_disk_next = zi->number_disk_with_CD - 1; - err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); - if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) - err = zipGoToSpecificDisk(file, number_disk_next, 0); - if (err == ZIP_OK) - zi->number_disk = number_disk_next; - ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); - return err; -} - -/* Goes to the next disk in a spanned archive */ -local int zipGoToNextDisk OF((zipFile file)); -local int zipGoToNextDisk(zipFile file) -{ - zip64_internal* zi; - ZPOS64_T size_available_in_disk; - int err = ZIP_OK; - int number_disk_next; - - zi = (zip64_internal*)file; - - if (zi->disk_size == 0) - return err; - - number_disk_next = zi->number_disk + 1; - - do - { - err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); - if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) - err = zipGoToSpecificDisk(file, number_disk_next, 0); - if (err != ZIP_OK) - break; - err = zipGetDiskSizeAvailable(file, &size_available_in_disk); - if (err != ZIP_OK) - break; - zi->number_disk = number_disk_next; - zi->number_disk_with_CD = zi->number_disk + 1; - - number_disk_next += 1; - } - while (size_available_in_disk <= 0); - - return err; -} - -/* Locate the Central directory of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); -local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T file_size; - ZPOS64_T back_read = 4; - ZPOS64_T max_back=0xffff; /* maximum size of global comment */ - ZPOS64_T pos_found=0; - uLong read_size; - ZPOS64_T read_pos; - int i; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf == NULL) - return 0; - - if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) - { - TRYFREE(buf); - return 0; - } - - file_size = ZTELL64(*pzlib_filefunc_def, filestream); - - if (max_back > file_size) - max_back = file_size; - - while (back_read < max_back) - { - if (back_read + BUFREADCOMMENT > max_back) - back_read = max_back; - else - back_read += BUFREADCOMMENT; - - read_pos = file_size-back_read; - read_size = ((BUFREADCOMMENT+4) < (file_size-read_pos)) ? - (BUFREADCOMMENT+4) : (uLong)(file_size-read_pos); - - if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - break; - if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) - break; - - for (i = (int)read_size-3; (i--) > 0;) - if ((*(buf+i)) == (ENDHEADERMAGIC & 0xff) && - (*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff) && - (*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff) && - (*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)) - { - pos_found = read_pos+i; - break; - } - - if (pos_found != 0) - break; - } - TRYFREE(buf); - return pos_found; -} - -/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - const ZPOS64_T endcentraloffset)); -local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, - const ZPOS64_T endcentraloffset) -{ - ZPOS64_T offset; - uLong uL; - - /* Zip64 end of central directory locator */ - if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) - return 0; - - /* read locator signature */ - if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) - return 0; - if (uL != ZIP64ENDLOCHEADERMAGIC) - return 0; - /* number of the disk with the start of the zip64 end of central directory */ - if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) - return 0; - /* relative offset of the zip64 end of central directory record */ - if (zip64local_getLong64(pzlib_filefunc_def, filestream, &offset) != ZIP_OK) - return 0; - /* total number of disks */ - if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) - return 0; - /* Goto end of central directory record */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) - return 0; - /* the signature */ - if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) - return 0; - if (uL != ZIP64ENDHEADERMAGIC) - return 0; - - return offset; -} - -extern zipFile ZEXPORT zipOpen4(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, - zlib_filefunc64_32_def* pzlib_filefunc64_32_def) -{ - zip64_internal ziinit; - zip64_internal* zi; -#ifndef NO_ADDFILEINEXISTINGZIP - ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ - ZPOS64_T size_central_dir; /* size of the central directory */ - ZPOS64_T offset_central_dir; /* offset of start of central directory */ - ZPOS64_T number_entry_CD; /* total number of entries in the central dir */ - ZPOS64_T number_entry; - ZPOS64_T central_pos; - ZPOS64_T size_central_dir_to_read; - uLong uL; - uLong size_comment; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read; -#endif - int err = ZIP_OK; - int mode; - - ziinit.z_filefunc.zseek32_file = NULL; - ziinit.z_filefunc.ztell32_file = NULL; - if (pzlib_filefunc64_32_def == NULL) - fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); - else - ziinit.z_filefunc = *pzlib_filefunc64_32_def; - - if (append == APPEND_STATUS_CREATE) - mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE); - else - mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING); - - ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, mode); - if (ziinit.filestream == NULL) - return NULL; - - if (append == APPEND_STATUS_CREATEAFTER) - { - /* Don't support spanning ZIP with APPEND_STATUS_CREATEAFTER */ - if (disk_size > 0) - return NULL; - - ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); - } - - ziinit.filestream_with_CD = ziinit.filestream; - ziinit.append = append; - ziinit.number_disk = 0; - ziinit.number_disk_with_CD = 0; - ziinit.disk_size = disk_size; - ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); - ziinit.in_opened_file_inzip = 0; - ziinit.ci.stream_initialised = 0; - ziinit.number_entry = 0; - ziinit.add_position_when_writting_offset = 0; - init_linkedlist(&(ziinit.central_dir)); - - zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); - if (zi == NULL) - { - ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - -#ifndef NO_ADDFILEINEXISTINGZIP - /* Add file in a zipfile */ - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - /* Read and Cache Central Directory Records */ - central_pos = zip64local_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); - /* disable to allow appending to empty ZIP archive (must be standard zip, not zip64) - if (central_pos == 0) - err = ZIP_ERRNO; - */ - - if (err == ZIP_OK) - { - /* read end of central directory info */ - if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - /* number of this disk */ - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) - err = ZIP_ERRNO; - /* number of the disk with the start of the central directory */ - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) - err = ZIP_ERRNO; - /* total number of entries in the central dir on this disk */ - number_entry = 0; - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - else - number_entry = uL; - /* total number of entries in the central dir */ - number_entry_CD = 0; - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - else - number_entry_CD = uL; - if (number_entry_CD!=number_entry) - err = ZIP_BADZIPFILE; - /* size of the central directory */ - size_central_dir = 0; - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - else - size_central_dir = uL; - /* offset of start of central directory with respect to the starting disk number */ - offset_central_dir = 0; - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - else - offset_central_dir = uL; - /* zipfile global comment length */ - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &size_comment) != ZIP_OK) - err = ZIP_ERRNO; - - if ((err == ZIP_OK) && ((number_entry_CD == 0xffff) || (offset_central_dir == 0xffffffff))) - { - /* Format should be Zip64, as the central directory or file size is too large */ - central_pos = zip64local_SearchCentralDir64(&ziinit.z_filefunc, ziinit.filestream, central_pos); - - if (central_pos) - { - ZPOS64_T sizeEndOfCentralDirectory; - - if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - /* size of zip64 end of central directory record */ - if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &sizeEndOfCentralDirectory) != ZIP_OK) - err = ZIP_ERRNO; - /* version made by */ - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - /* version needed to extract */ - if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) - err = ZIP_ERRNO; - /* number of this disk */ - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) - err = ZIP_ERRNO; - /* number of the disk with the start of the central directory */ - if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) - err = ZIP_ERRNO; - /* total number of entries in the central directory on this disk */ - if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry) != ZIP_OK) - err = ZIP_ERRNO; - /* total number of entries in the central directory */ - if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry_CD) != ZIP_OK) - err = ZIP_ERRNO; - if (number_entry_CD!=number_entry) - err = ZIP_BADZIPFILE; - /* size of the central directory */ - if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &size_central_dir) != ZIP_OK) - err = ZIP_ERRNO; - /* offset of start of central directory with respect to the starting disk number */ - if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &offset_central_dir) != ZIP_OK) - err = ZIP_ERRNO; - } - else - err = ZIP_BADZIPFILE; - } - } - - if ((err == ZIP_OK) && (central_pos 0) - { - ziinit.globalcomment = (char*)ALLOC(size_comment+1); - if (ziinit.globalcomment) - { - size_comment = ZREAD64(ziinit.z_filefunc, ziinit.filestream, ziinit.globalcomment, size_comment); - ziinit.globalcomment[size_comment] = 0; - } - } - - byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); - ziinit.add_position_when_writting_offset = byte_before_the_zipfile; - - /* Store central directory in memory */ - size_central_dir_to_read = size_central_dir; - buf_size = SIZEDATA_INDATABLOCK; - buf_read = (void*)ALLOC(buf_size); - - if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - - while ((size_central_dir_to_read > 0) && (err == ZIP_OK)) - { - ZPOS64_T read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - - if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, buf_read, (uLong)read_this) != read_this) - err = ZIP_ERRNO; - - if (err == ZIP_OK) - err = add_data_in_datablock(&ziinit.central_dir, buf_read, (uLong)read_this); - - size_central_dir_to_read -= read_this; - } - TRYFREE(buf_read); - - ziinit.begin_pos = byte_before_the_zipfile; - ziinit.number_entry = number_entry_CD; - - if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir+byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - } - - if (globalcomment) - *globalcomment = ziinit.globalcomment; -#endif - - if (err != ZIP_OK) - { -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -#endif - TRYFREE(zi); - return NULL; - } - - *zi = ziinit; - zipGoToFirstDisk((zipFile)zi); - return(zipFile)zi; -} - -extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc32_def) -{ - if (pzlib_filefunc32_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); - return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); - } - return zipOpen4(pathname, append, 0, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def) -{ - if (pzlib_filefunc_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; - zlib_filefunc64_32_def_fill.ztell32_file = NULL; - zlib_filefunc64_32_def_fill.zseek32_file = NULL; - return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); - } - return zipOpen4(pathname, append, 0, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen3(const char *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc32_def) -{ - if (pzlib_filefunc32_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); - return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); - } - return zipOpen4(pathname, append, disk_size, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen3_64(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def) -{ - if (pzlib_filefunc_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; - zlib_filefunc64_32_def_fill.ztell32_file = NULL; - zlib_filefunc64_32_def_fill.zseek32_file = NULL; - return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); - } - return zipOpen4(pathname, append, disk_size, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen(const char* pathname, int append) -{ - return zipOpen3((const void*)pathname,append,0,NULL,NULL); -} - -extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) -{ - return zipOpen3(pathname,append,0,NULL,NULL); -} - -extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, - int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) -{ - zip64_internal* zi; - uInt size_filename; - uInt size_comment = 0; - uInt i; - int err = ZIP_OK; - ZPOS64_T size_available; - ZPOS64_T size_needed; - -#ifdef NOCRYPT - (crcForCrypting); - if (password != NULL) - return ZIP_PARAMERROR; -#endif - - if (file == NULL) - return ZIP_PARAMERROR; - - if ((method != 0) && -#ifdef HAVE_BZIP2 - (method != Z_BZIP2ED) && -#endif - (method != Z_DEFLATED)) - return ZIP_PARAMERROR; - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - if (filename == NULL) - filename = "-"; - if (comment != NULL) - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else - zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); - } - - zi->ci.method = method; - zi->ci.compression_method = method; - zi->ci.crc32 = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.flag = flagBase; - if ((level == 8) || (level == 9)) - zi->ci.flag |= 2; - if (level == 2) - zi->ci.flag |= 4; - if (level == 1) - zi->ci.flag |= 6; - if (password != NULL) - { - zi->ci.flag |= 1; -#ifdef HAVE_AES - zi->ci.method = AES_METHOD; -#endif - } - - if (zi->disk_size > 0) - { - if ((zi->number_disk == 0) && (zi->number_entry == 0)) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)DISKHEADERMAGIC, 4); - - /* Make sure enough space available on current disk for local header */ - zipGetDiskSizeAvailable((zipFile)zi, &size_available); - size_needed = 30 + size_filename + size_extrafield_local; - if (zi->ci.zip64) - size_needed += 20; -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - size_needed += 11; -#endif - if (size_available < size_needed) - zipGoToNextDisk((zipFile)zi); - } - - zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream); - zi->ci.size_comment = size_comment; - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global; - zi->ci.size_centralextra = size_extrafield_global; - zi->ci.size_centralextrafree = 32; /* Extra space reserved for ZIP64 extra info */ -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - zi->ci.size_centralextrafree += 11; /* Extra space reserved for AES extra info */ -#endif - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralextrafree + size_comment); - zi->ci.number_disk = zi->number_disk; - - /* Write central directory header */ - zip64local_putValue_inmemory(zi->ci.central_header, (uLong)CENTRALHEADERMAGIC, 4); - zip64local_putValue_inmemory(zi->ci.central_header+4, (uLong)versionMadeBy, 2); - zip64local_putValue_inmemory(zi->ci.central_header+6, (uLong)20, 2); - zip64local_putValue_inmemory(zi->ci.central_header+8, (uLong)zi->ci.flag, 2); - zip64local_putValue_inmemory(zi->ci.central_header+10, (uLong)zi->ci.method, 2); - zip64local_putValue_inmemory(zi->ci.central_header+12, (uLong)zi->ci.dosDate, 4); - zip64local_putValue_inmemory(zi->ci.central_header+16, (uLong)0, 4); /*crc*/ - zip64local_putValue_inmemory(zi->ci.central_header+20, (uLong)0, 4); /*compr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+24, (uLong)0, 4); /*uncompr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+28, (uLong)size_filename, 2); - zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)size_extrafield_global, 2); - zip64local_putValue_inmemory(zi->ci.central_header+32, (uLong)size_comment, 2); - zip64local_putValue_inmemory(zi->ci.central_header+34, (uLong)zi->ci.number_disk, 2); /*disk nm start*/ - - if (zipfi == NULL) - zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)0, 2); - else - zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)zipfi->internal_fa, 2); - if (zipfi == NULL) - zip64local_putValue_inmemory(zi->ci.central_header+38, (uLong)0, 4); - else - zip64local_putValue_inmemory(zi->ci.central_header+38, (uLong)zipfi->external_fa, 4); - if (zi->ci.pos_local_header >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+42, (uLong)0xffffffff, 4); - else - zip64local_putValue_inmemory(zi->ci.central_header+42, - (uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset, 4); - - for (i = 0; i < size_filename; i++) - zi->ci.central_header[SIZECENTRALHEADER+i] = filename[i]; - for (i = 0; i < size_extrafield_global; i++) - zi->ci.central_header[SIZECENTRALHEADER+size_filename+i] = - ((const char*)extrafield_global)[i]; - /* Store comment at the end for later repositioning */ - for (i = 0; i < size_comment; i++) - zi->ci.central_header[zi->ci.size_centralheader+ - zi->ci.size_centralextrafree+i] = comment[i]; - - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - zi->ci.zip64 = zip64; - zi->ci.total_compressed = 0; - zi->ci.total_uncompressed = 0; - zi->ci.pos_zip64extrainfo = 0; - - /* Write the local header */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)LOCALHEADERMAGIC, 4); - - if (err == ZIP_OK) - { - if (zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* version needed to extract */ - else - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)20, 2); /* version needed to extract */ - } - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.flag, 2); - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.method, 2); - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.dosDate, 4); - - /* CRC & compressed size & uncompressed size will be filled in later and rewritten later */ - - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* crc 32, unknown */ - if (err == ZIP_OK) - { - if (zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); /* compressed size, unknown */ - else - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* compressed size, unknown */ - } - if (err == ZIP_OK) - { - if (zi->ci.zip64) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); - else /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); - } - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_filename, 2); - if (err == ZIP_OK) - { - ZPOS64_T size_extrafield = size_extrafield_local; - if (zi->ci.zip64) - size_extrafield += 20; -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - size_extrafield += 11; -#endif - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_extrafield,2); - } - if ((err == ZIP_OK) && (size_filename > 0)) - { - if (ZWRITE64(zi->z_filefunc, zi->filestream, filename, size_filename) != size_filename) - err = ZIP_ERRNO; - } - if ((err == ZIP_OK) && (size_extrafield_local > 0)) - { - if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) - err = ZIP_ERRNO; - } - - /* Write the Zip64 extended info */ - if ((err == ZIP_OK) && (zi->ci.zip64)) - { - short headerid = 1; - short datasize = 16; - ZPOS64_T compressed_size = 0; - ZPOS64_T uncompressed_size = 0; - - /* Remember position of Zip64 extended info for the local file header. - (needed when we update size after done with file) */ - zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc, zi->filestream); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)headerid, 2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)datasize, 2); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)uncompressed_size, 8); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)compressed_size, 8); - } -#ifdef HAVE_AES - /* Write the AES extended info */ - if ((err == ZIP_OK) && (zi->ci.method == AES_METHOD)) - { - int headerid = 0x9901; - short datasize = 7; - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, headerid, 2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, datasize, 2); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_VERSION, 2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'A', 1); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'E', 1); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_ENCRYPTIONMODE, 1); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->ci.compression_method, 2); - } -#endif - -#ifdef HAVE_BZIP2 - zi->ci.bstream.avail_in = (uInt)0; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - zi->ci.bstream.total_in_hi32 = 0; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_out_hi32 = 0; - zi->ci.bstream.total_out_lo32 = 0; -#endif - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - zi->ci.stream.data_type = Z_BINARY; - - if ((err == ZIP_OK) && (!zi->ci.raw)) - { - if (method == Z_DEFLATED) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)zi; - - if (windowBits > 0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); - - if (err == Z_OK) - zi->ci.stream_initialised = Z_DEFLATED; - } - else if (method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - zi->ci.bstream.bzalloc = 0; - zi->ci.bstream.bzfree = 0; - zi->ci.bstream.opaque = (voidpf)0; - - err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0, 35); - if (err == BZ_OK) - zi->ci.stream_initialised = Z_BZIP2ED; -#endif - } - } - -#ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err == Z_OK) && ((zi->ci.flag & 1) != 0)) - { -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - { - unsigned char passverify[AES_PWVERIFYSIZE]; - unsigned char saltvalue[AES_MAXSALTLENGTH]; - uInt saltlength; - - if ((AES_ENCRYPTIONMODE < 1) || (AES_ENCRYPTIONMODE > 3)) - return Z_ERRNO; - - saltlength = SALT_LENGTH(AES_ENCRYPTIONMODE); - - prng_init(entropy_fun, zi->ci.aes_rng); - prng_rand(saltvalue, saltlength, zi->ci.aes_rng); - prng_end(zi->ci.aes_rng); - - fcrypt_init(AES_ENCRYPTIONMODE, password, strlen(password), saltvalue, passverify, &zi->ci.aes_ctx); - - if (ZWRITE64(zi->z_filefunc, zi->filestream, saltvalue, saltlength) != saltlength) - err = ZIP_ERRNO; - if (ZWRITE64(zi->z_filefunc, zi->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) - err = ZIP_ERRNO; - - zi->ci.crypt_header_size = saltlength + AES_PWVERIFYSIZE + AES_AUTHCODESIZE; - } - else -#endif - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - - zi->ci.pcrc_32_tab = (const unsigned long *)get_crc_table(); - /*init_keys(password, zi->ci.keys, zi->ci.pcrc_32_tab);*/ - - sizeHead = crypthead(password, bufHead, RAND_HEAD_LEN, zi->ci.keys, zi->ci.pcrc_32_tab, crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE64(zi->z_filefunc, zi->filestream, bufHead, sizeHead) != sizeHead) - err = ZIP_ERRNO; - } - } -#endif - - if (err == Z_OK) - zi->in_opened_file_inzip = 1; - return err; -} - -extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, - int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, - strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, - int memLevel, int strategy, const char* password, uLong crcForCrypting) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, - strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, - int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level, int zip64) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, - uInt size_extrafield_global, const char* comment, int method, int level) -{ - return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); -} - -/* Flushes the write buffer to disk */ -local int zip64FlushWriteBuffer OF((zip64_internal* zi)); -local int zip64FlushWriteBuffer(zip64_internal* zi) -{ - int err = ZIP_OK; - uInt written = 0; - uInt total_written = 0; - uInt write = 0; - uInt max_write = 0; - ZPOS64_T size_available = 0; - - if ((zi->ci.flag & 1) != 0) - { -#ifndef NOCRYPT -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - { - fcrypt_encrypt(zi->ci.buffered_data, zi->ci.pos_in_buffered_data, &zi->ci.aes_ctx); - } - else -#endif - { - uInt i; - int t; - for (i = 0;i < zi->ci.pos_in_buffered_data; i++) - zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); - } -#endif - } - - write = zi->ci.pos_in_buffered_data; - - do - { - max_write = write; - - if (zi->disk_size > 0) - { - err = zipGetDiskSizeAvailable((zipFile)zi, &size_available); - if (err != ZIP_OK) - return err; - - if (size_available == 0) - { - err = zipGoToNextDisk((zipFile)zi); - if (err != ZIP_OK) - return err; - } - - if (size_available < (ZPOS64_T)max_write) - max_write = (uInt)size_available; - } - - written = ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data + total_written, max_write); - - if (ZERROR64(zi->z_filefunc, zi->filestream)) - { - err = ZIP_ERRNO; - break; - } - - total_written += written; - write -= written; - } - while (write > 0); - - zi->ci.total_compressed += zi->ci.pos_in_buffered_data; - -#ifdef HAVE_BZIP2 - if (zi->ci.compression_method == Z_BZIP2ED) - { - zi->ci.total_uncompressed += zi->ci.bstream.total_in_lo32; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_in_hi32 = 0; - } - else -#endif - { - zi->ci.total_uncompressed += zi->ci.stream.total_in; - zi->ci.stream.total_in = 0; - } - - zi->ci.pos_in_buffered_data = 0; - - return err; -} - -extern int ZEXPORT zipWriteInFileInZip(zipFile file,const void* buf,unsigned int len) -{ - zip64_internal* zi; - int err = ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.crc32 = crc32(zi->ci.crc32, buf, (uInt)len); - -#ifdef HAVE_BZIP2 - if ((zi->ci.compression_method == Z_BZIP2ED) && (!zi->ci.raw)) - { - zi->ci.bstream.next_in = (void*)buf; - zi->ci.bstream.avail_in = len; - err = BZ_RUN_OK; - - while ((err == BZ_RUN_OK) && (zi->ci.bstream.avail_in > 0)) - { - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - else - { - uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; - uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; - - err = BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo); - } - } - - if (err == BZ_RUN_OK) - err = ZIP_OK; - } - else -#endif - { - zi->ci.stream.next_in = (Bytef*)buf; - zi->ci.stream.avail_in = len; - - while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - if (err != ZIP_OK) - break; - - if ((zi->ci.compression_method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong total_out_before = zi->ci.stream.total_out; - err = deflate(&zi->ci.stream, Z_NO_FLUSH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); - } - else - { - uInt copy_this,i; - if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) - copy_this = zi->ci.stream.avail_in; - else - copy_this = zi->ci.stream.avail_out; - - for (i = 0; i < copy_this; i++) - *(((char*)zi->ci.stream.next_out)+i) = - *(((const char*)zi->ci.stream.next_in)+i); - - zi->ci.stream.avail_in -= copy_this; - zi->ci.stream.avail_out -= copy_this; - zi->ci.stream.next_in += copy_this; - zi->ci.stream.next_out += copy_this; - zi->ci.stream.total_in += copy_this; - zi->ci.stream.total_out += copy_this; - zi->ci.pos_in_buffered_data += copy_this; - } - } - } - - return err; -} - -extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) -{ - return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); -} - -extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) -{ - zip64_internal* zi; - ZPOS64_T compressed_size; - uLong invalidValue = 0xffffffff; - uLong i = 0; - short datasize = 0; - int err = ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if (!zi->ci.raw) - { - if (zi->ci.compression_method == Z_DEFLATED) - { - while (err == ZIP_OK) - { - uLong total_out_before; - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - total_out_before = zi->ci.stream.total_out; - err = deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); - } - } - else if (zi->ci.compression_method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - err = BZ_FINISH_OK; - while (err == BZ_FINISH_OK) - { - uLong total_out_before; - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - total_out_before = zi->ci.bstream.total_out_lo32; - err = BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); - if (err == BZ_STREAM_END) - err = Z_STREAM_END; - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - total_out_before); - } - - if (err == BZ_FINISH_OK) - err = ZIP_OK; -#endif - } - } - - if (err == Z_STREAM_END) - err = ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err == ZIP_OK)) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - } - -#ifdef HAVE_AES - if (zi->ci.method == AES_METHOD) - { - unsigned char authcode[AES_AUTHCODESIZE]; - - fcrypt_end(authcode, &zi->ci.aes_ctx); - - if (ZWRITE64(zi->z_filefunc, zi->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) - err = ZIP_ERRNO; - } -#endif - - if (!zi->ci.raw) - { - if (zi->ci.compression_method == Z_DEFLATED) - { - int tmp_err = deflateEnd(&zi->ci.stream); - if (err == ZIP_OK) - err = tmp_err; - zi->ci.stream_initialised = 0; - } -#ifdef HAVE_BZIP2 - else if (zi->ci.compression_method == Z_BZIP2ED) - { - int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); - if (err == ZIP_OK) - err = tmperr; - zi->ci.stream_initialised = 0; - } -#endif - - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = zi->ci.total_uncompressed; - } - - compressed_size = zi->ci.total_compressed; -#ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -#endif - - /* Update current item crc and sizes */ - if (compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) - { - zip64local_putValue_inmemory(zi->ci.central_header+4, (uLong)45, 2); /* version made by */ - zip64local_putValue_inmemory(zi->ci.central_header+6, (uLong)45, 2); /* version needed */ - } - zip64local_putValue_inmemory(zi->ci.central_header+16, crc32, 4); /* crc */ - if (compressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue, 4); /* compr size */ - else - zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size, 4); /* compr size */ - if (zi->ci.stream.data_type == Z_ASCII) - zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)Z_ASCII, 2); /* internal file attrib */ - if (uncompressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue, 4); /* uncompr size */ - else - zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size, 4); /* uncompr size */ - - /* Add ZIP64 extra info field for uncompressed size */ - if (uncompressed_size >= 0xffffffff) - datasize += 8; - /* Add ZIP64 extra info field for compressed size */ - if (compressed_size >= 0xffffffff) - datasize += 8; - /* Add ZIP64 extra info field for relative offset to local file header of current file */ - if (zi->ci.pos_local_header >= 0xffffffff) - datasize += 8; - - /* Add Extra Information Header for 'ZIP64 information' */ - if (datasize > 0) - { - char* p = zi->ci.central_header + zi->ci.size_centralheader; - - if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) - return ZIP_BADZIPFILE; - - zip64local_putValue_inmemory(p, 0x0001, 2); - p += 2; - zip64local_putValue_inmemory(p, datasize, 2); - p += 2; - - if (uncompressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, uncompressed_size, 8); - p += 8; - } - if (compressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, compressed_size, 8); - p += 8; - } - if (zi->ci.pos_local_header >= 0xffffffff) - { - zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); - p += 8; - } - - zi->ci.size_centralextrafree -= datasize + 4; - zi->ci.size_centralheader += datasize + 4; - zi->ci.size_centralextra += datasize + 4; - - zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)zi->ci.size_centralextra, 2); - } - -#ifdef HAVE_AES - /* Write the AES extended info */ - if (zi->ci.method == AES_METHOD) - { - char* p = zi->ci.central_header + zi->ci.size_centralheader; - - datasize = 7; - - if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) - return ZIP_BADZIPFILE; - - zip64local_putValue_inmemory(p, 0x9901, 2); - p += 2; - zip64local_putValue_inmemory(p, datasize, 2); - p += 2; - zip64local_putValue_inmemory(p, AES_VERSION, 2); - p += 2; - zip64local_putValue_inmemory(p, 'A', 1); - p += 1; - zip64local_putValue_inmemory(p, 'E', 1); - p += 1; - zip64local_putValue_inmemory(p, AES_ENCRYPTIONMODE, 1); - p += 1; - zip64local_putValue_inmemory(p, zi->ci.compression_method, 2); - p += 2; - - zi->ci.size_centralextrafree -= datasize + 4; - zi->ci.size_centralheader += datasize + 4; - zi->ci.size_centralextra += datasize + 4; - - zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)zi->ci.size_centralextra, 2); - } -#endif - /* Restore comment to correct position */ - for (i = 0; i < zi->ci.size_comment; i++) - zi->ci.central_header[zi->ci.size_centralheader+i] = - zi->ci.central_header[zi->ci.size_centralheader+zi->ci.size_centralextrafree+i]; - zi->ci.size_centralheader += zi->ci.size_comment; - - if (err == ZIP_OK) - err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); - - free(zi->ci.central_header); - - if (err == ZIP_OK) - { - /* Update the LocalFileHeader with the new values. */ - ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); - uLong cur_number_disk = zi->number_disk; - - /* Local file header is stored on previous disk, switch to make edits */ - if (zi->ci.number_disk != cur_number_disk) - err = zipGoToSpecificDisk(file, zi->ci.number_disk, 1); - - if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_local_header + 14, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream,crc32,4); /* crc 32, unknown */ - - if (uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff) - { - if (zi->ci.pos_zip64extrainfo > 0) - { - /* Update the size in the ZIP64 extended field. */ - if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_zip64extrainfo + 4, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - - if (err == ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); - if (err == ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); - } - else - err = ZIP_BADZIPFILE; /* Caller passed zip64 = 0, so no room for zip64 info -> fatal */ - } - else - { - if (err == ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream,compressed_size, 4); - if (err == ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream,uncompressed_size, 4); - } - - /* Now switch back again to the disk we were on before */ - if (zi->ci.number_disk != cur_number_disk) - err = zipGoToSpecificDisk(file, cur_number_disk, 1); - - if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip, ZLIB_FILEFUNC_SEEK_SET) != 0) - err = ZIP_ERRNO; - } - - zi->number_entry++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip(zipFile file) -{ - return zipCloseFileInZipRaw(file, 0, 0); -} - -extern int ZEXPORT zipClose(zipFile file, const char* global_comment) -{ - zip64_internal* zi; - int err = 0; - uLong size_centraldir = 0; - uInt size_global_comment = 0; - ZPOS64_T centraldir_pos_inzip; - ZPOS64_T pos = 0; - uLong write = 0; - - if (file == NULL) - return ZIP_PARAMERROR; - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - err = zipCloseFileInZip(file); - -#ifndef NO_ADDFILEINEXISTINGZIP - if (global_comment == NULL) - global_comment = zi->globalcomment; -#endif - - if (zi->filestream != zi->filestream_with_CD) - { - if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - if (zi->disk_size > 0) - zi->number_disk_with_CD = zi->number_disk + 1; - zi->filestream = zi->filestream_with_CD; - } - - centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); - - if (err == ZIP_OK) - { - linkedlist_datablock_internal* ldi = zi->central_dir.first_block; - while (ldi!= NULL) - { - if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0)) - { - write = ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data, ldi->filled_in_this_block); - if (write != ldi->filled_in_this_block) - err = ZIP_ERRNO; - } - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - - free_linkedlist(&(zi->central_dir)); - - pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - - /* Write the ZIP64 central directory header */ - if (pos >= 0xffffffff || zi->number_entry > 0xffff) - { - ZPOS64_T zip64eocd_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); - uLong zip64datasize = 44; - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDHEADERMAGIC, 4); - - /* size of this 'zip64 end of central directory' */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)zip64datasize, 8); - /* version made by */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); - /* version needed */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); - /* number of this disk */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); - /* number of the disk with the start of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); - /* total number of entries in the central dir on this disk */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - /* total number of entries in the central dir */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - /* size of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)size_centraldir, 8); - - if (err == ZIP_OK) - { - /* offset of start of central directory with respect to the starting disk number */ - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)pos, 8); - } - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDLOCHEADERMAGIC, 4); - - /* number of the disk with the start of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); - /*relative offset to the Zip64EndOfCentralDirectory */ - if (err == ZIP_OK) - { - ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8); - } - /* number of the disk with the start of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD+1, 4); - } - - /* Write the central directory header */ - - /* signature */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ENDHEADERMAGIC, 4); - /* number of this disk */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); - /* number of the disk with the start of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); - /* total number of entries in the central dir on this disk */ - if (err == ZIP_OK) - { - if (zi->number_entry >= 0xffff) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ - else - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); - } - /* total number of entries in the central dir */ - if (err == ZIP_OK) - { - if (zi->number_entry >= 0xffff) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ - else - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); - } - /* size of the central directory */ - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_centraldir,4); - /* offset of start of central directory with respect to the starting disk number */ - if (err == ZIP_OK) - { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - if (pos >= 0xffffffff) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffffffff, 4); - else - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)pos, 4); - } - - /* Write global comment */ - - if (global_comment != NULL) - size_global_comment = (uInt)strlen(global_comment); - if (err == ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_global_comment, 2); - if (err == ZIP_OK && size_global_comment > 0) - { - if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment, size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - } - - if ((ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) && (err == ZIP_OK)) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project + + Copyright (C) 1998-2010 Gilles Vollant + http://www.winimage.com/zLibDll/minizip.html + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson + http://result42.com + Modifications for AES, PKWARE disk spanning + Copyright (C) 2010-2014 Nathan Moinvaziri + + This program is distributed under the terms of the same license as zlib. + See the accompanying LICENSE file for the full text of the license. +*/ + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifdef HAVE_AES +# define AES_METHOD (99) +# define AES_PWVERIFYSIZE (2) +# define AES_AUTHCODESIZE (10) +# define AES_MAXSALTLENGTH (16) +# define AES_VERSION (0x0001) +# define AES_ENCRYPTIONMODE (0x03) + +# include "aes/aes.h" +# include "aes/fileenc.h" +# include "aes/prng.h" +# include "aes/entropy.h" +#endif + +#ifndef NOCRYPT +# define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +# include "crypt.h" +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define DISKHEADERMAGIC (0x08074b50) +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x06064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x07064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ +#define SIZECENTRALHEADERLOCATOR (0x14) /* 20 */ +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +#ifndef BUFREADCOMMENT +# define BUFREADCOMMENT (0x400) +#endif +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform dependent */ +#endif + +#ifndef Z_BUFSIZE +# define Z_BUFSIZE (64*1024) +#endif +#ifndef Z_MAXFILENAMEINZIP +# define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* NOT sure that this work on ALL platform */ +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif + +const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignment */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif +#ifdef HAVE_AES + fcrypt_ctx aes_ctx; + prng_ctx aes_rng[1]; +#endif + int stream_initialised; /* 1 is stream is initialized */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file currently writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralextra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralextrafree; /* Extra bytes allocated to the central header but that are not used */ + uLong size_comment; + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method written to file.*/ + int compression_method; /* compression method to use */ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE]; /* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int zip64; /* Add ZIP64 extended information in the extra field */ + uLong number_disk; /* number of current disk used for spanning ZIP */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T total_compressed; + ZPOS64_T total_uncompressed; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structure of the zipfile */ + voidpf filestream_with_CD; /* io structure of the zipfile with the central dir */ + linkedlist_data central_dir; /* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + int append; /* append mode */ + curfile64_info ci; /* info on the file currently writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + ZPOS64_T disk_size; /* size of each disk */ + uLong number_disk; /* number of the current disk, used for spanning ZIP */ + uLong number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */ +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif +} zip64_internal; + +/* Allocate a new data block */ +local linkedlist_datablock_internal* allocate_new_datablock OF(()); +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + + ldi = (linkedlist_datablock_internal*)ALLOC(sizeof(linkedlist_datablock_internal)); + + if (ldi != NULL) + { + ldi->next_datablock = NULL; + ldi->filled_in_this_block = 0; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK; + } + return ldi; +} + +/* Free data block in linked list */ +local void free_datablock OF((linkedlist_datablock_internal* ldi)); +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi != NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +/* Initialize linked list */ +local void init_linkedlist OF((linkedlist_data* ll)); +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +/* Free entire linked list and all data blocks */ +local void free_linkedlist OF((linkedlist_data* ll)); +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + +/* Add data to linked list data block */ +local int add_data_in_datablock OF((linkedlist_data* ll, const void* buf, uLong len)); +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll == NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block == 0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + +local uLong zip64local_TmzDateToDosDate OF((const tm_zip* ptm)); +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year; +#define zip64local_in_range(min, max, value) ((min) <= (value) && (value) <= (max)) + /* Years supported: + * [00, 79] (assumed to be between 2000 and 2079) + * [80, 207] (assumed to be between 1980 and 2107, typical output of old + software that does 'year-1900' to get a double digit year) + * [1980, 2107] + Due to the date format limitations, only years between 1980 and 2107 can be stored. + */ + if (!(zip64local_in_range(1980, 2107, ptm->tm_year) || zip64local_in_range(0, 207, ptm->tm_year)) || + !zip64local_in_range(0, 11, ptm->tm_mon) || + !zip64local_in_range(1, 31, ptm->tm_mday) || + !zip64local_in_range(0, 23, ptm->tm_hour) || + !zip64local_in_range(0, 59, ptm->tm_min) || + !zip64local_in_range(0, 59, ptm->tm_sec)) + return 0; +#undef zip64local_in_range + + year = (uLong)ptm->tm_year; + if (year >= 1980) /* range [1980, 2107] */ + year -= 1980; + else if (year >= 80) /* range [80, 99] */ + year -= 80; + else /* range [00, 79] */ + year += 20; + + return + (uLong)(((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + +/* Inputs a long in LSB order to the given file: nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { + /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf =(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { + /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def, filestream, &c,1); + if (err == 1) + { + *pi = (int)c; + return ZIP_OK; + } + if (ZERROR64(*pzlib_filefunc_def, filestream)) + return ZIP_ERRNO; + return ZIP_EOF; +} + +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i) << 8; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (uLong)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i)<<8; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i)<<16; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((uLong)i)<<24; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x = (ZPOS64_T)i; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<8; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<16; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<24; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<32; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<40; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<48; + if (err == ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def, filestream, &i); + x += ((ZPOS64_T)i)<<56; + + if (err == ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +/* Gets the amount of bytes left to write to the current disk for spanning archives */ +local int zipGetDiskSizeAvailable OF((zipFile file, ZPOS64_T *size_available)); +local int zipGetDiskSizeAvailable(zipFile file, ZPOS64_T *size_available) +{ + zip64_internal* zi; + ZPOS64_T current_disk_size; + + zi = (zip64_internal*)file; + ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); + current_disk_size = ZTELL64(zi->z_filefunc, zi->filestream); + *size_available = zi->disk_size - current_disk_size; + return ZIP_OK; +} + +/* Goes to a specific disk number for spanning archives */ +local int zipGoToSpecificDisk OF((zipFile file, int number_disk, int open_existing)); +local int zipGoToSpecificDisk(zipFile file, int number_disk, int open_existing) +{ + zip64_internal* zi; + int err = ZIP_OK; + + zi = (zip64_internal*)file; + if (zi->disk_size == 0) + return err; + + if ((zi->filestream != NULL) && (zi->filestream != zi->filestream_with_CD)) + ZCLOSE64(zi->z_filefunc, zi->filestream); + + zi->filestream = ZOPENDISK64(zi->z_filefunc, zi->filestream_with_CD, number_disk, (open_existing == 1) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE)); + + if (zi->filestream == NULL) + err = ZIP_ERRNO; + + return err; +} + +/* Goes to the first disk in a spanned archive */ +local int zipGoToFirstDisk OF((zipFile file)); +local int zipGoToFirstDisk(zipFile file) +{ + zip64_internal* zi; + int number_disk_next; + int err = ZIP_OK; + + zi = (zip64_internal*)file; + + if (zi->disk_size == 0) + return err; + number_disk_next = 0; + if (zi->number_disk_with_CD > 0) + number_disk_next = zi->number_disk_with_CD - 1; + err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); + if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) + err = zipGoToSpecificDisk(file, number_disk_next, 0); + if (err == ZIP_OK) + zi->number_disk = number_disk_next; + ZSEEK64(zi->z_filefunc, zi->filestream, 0, ZLIB_FILEFUNC_SEEK_END); + return err; +} + +/* Goes to the next disk in a spanned archive */ +local int zipGoToNextDisk OF((zipFile file)); +local int zipGoToNextDisk(zipFile file) +{ + zip64_internal* zi; + ZPOS64_T size_available_in_disk; + int err = ZIP_OK; + int number_disk_next; + + zi = (zip64_internal*)file; + + if (zi->disk_size == 0) + return err; + + number_disk_next = zi->number_disk + 1; + + do + { + err = zipGoToSpecificDisk(file, number_disk_next, (zi->append == APPEND_STATUS_ADDINZIP)); + if ((err == ZIP_ERRNO) && (zi->append == APPEND_STATUS_ADDINZIP)) + err = zipGoToSpecificDisk(file, number_disk_next, 0); + if (err != ZIP_OK) + break; + err = zipGetDiskSizeAvailable(file, &size_available_in_disk); + if (err != ZIP_OK) + break; + zi->number_disk = number_disk_next; + zi->number_disk_with_CD = zi->number_disk + 1; + + number_disk_next += 1; + } + while (size_available_in_disk <= 0); + + return err; +} + +/* Locate the Central directory of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T file_size; + ZPOS64_T back_read = 4; + ZPOS64_T max_back=0xffff; /* maximum size of global comment */ + ZPOS64_T pos_found=0; + uLong read_size; + ZPOS64_T read_pos; + int i; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf == NULL) + return 0; + + if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0) + { + TRYFREE(buf); + return 0; + } + + file_size = ZTELL64(*pzlib_filefunc_def, filestream); + + if (max_back > file_size) + max_back = file_size; + + while (back_read < max_back) + { + if (back_read + BUFREADCOMMENT > max_back) + back_read = max_back; + else + back_read += BUFREADCOMMENT; + + read_pos = file_size-back_read; + read_size = ((BUFREADCOMMENT+4) < (file_size-read_pos)) ? + (BUFREADCOMMENT+4) : (uLong)(file_size-read_pos); + + if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + break; + if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size) + break; + + for (i = (int)read_size-3; (i--) > 0;) + if ((*(buf+i)) == (ENDHEADERMAGIC & 0xff) && + (*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff) && + (*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff) && + (*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)) + { + pos_found = read_pos+i; + break; + } + + if (pos_found != 0) + break; + } + TRYFREE(buf); + return pos_found; +} + +/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + const ZPOS64_T endcentraloffset)); +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, + const ZPOS64_T endcentraloffset) +{ + ZPOS64_T offset; + uLong uL; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + + /* read locator signature */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + if (uL != ZIP64ENDLOCHEADERMAGIC) + return 0; + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def, filestream, &offset) != ZIP_OK) + return 0; + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0) + return 0; + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def, filestream, &uL) != ZIP_OK) + return 0; + if (uL != ZIP64ENDHEADERMAGIC) + return 0; + + return offset; +} + +extern zipFile ZEXPORT zipOpen4(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; +#ifndef NO_ADDFILEINEXISTINGZIP + ZPOS64_T byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T number_entry_CD; /* total number of entries in the central dir */ + ZPOS64_T number_entry; + ZPOS64_T central_pos; + ZPOS64_T size_central_dir_to_read; + uLong uL; + uLong size_comment; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read; +#endif + int err = ZIP_OK; + int mode; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def == NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + if (append == APPEND_STATUS_CREATE) + mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE); + else + mode = (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING); + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, mode); + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + { + /* Don't support spanning ZIP with APPEND_STATUS_CREATEAFTER */ + if (disk_size > 0) + return NULL; + + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + } + + ziinit.filestream_with_CD = ziinit.filestream; + ziinit.append = append; + ziinit.number_disk = 0; + ziinit.number_disk_with_CD = 0; + ziinit.disk_size = disk_size; + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi == NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + +#ifndef NO_ADDFILEINEXISTINGZIP + /* Add file in a zipfile */ + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + /* Read and Cache Central Directory Records */ + central_pos = zip64local_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); + /* disable to allow appending to empty ZIP archive (must be standard zip, not zip64) + if (central_pos == 0) + err = ZIP_ERRNO; + */ + + if (err == ZIP_OK) + { + /* read end of central directory info */ + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* number of this disk */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) + err = ZIP_ERRNO; + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) + err = ZIP_ERRNO; + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + number_entry = uL; + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + number_entry_CD = uL; + if (number_entry_CD!=number_entry) + err = ZIP_BADZIPFILE; + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + size_central_dir = uL; + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + else + offset_central_dir = uL; + /* zipfile global comment length */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &size_comment) != ZIP_OK) + err = ZIP_ERRNO; + + if ((err == ZIP_OK) && ((number_entry_CD == 0xffff) || (offset_central_dir == 0xffffffff))) + { + /* Format should be Zip64, as the central directory or file size is too large */ + central_pos = zip64local_SearchCentralDir64(&ziinit.z_filefunc, ziinit.filestream, central_pos); + + if (central_pos) + { + ZPOS64_T sizeEndOfCentralDirectory; + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &sizeEndOfCentralDirectory) != ZIP_OK) + err = ZIP_ERRNO; + /* version made by */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* version needed to extract */ + if (zip64local_getShort(&ziinit.z_filefunc, ziinit.filestream, &uL) != ZIP_OK) + err = ZIP_ERRNO; + /* number of this disk */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk) != ZIP_OK) + err = ZIP_ERRNO; + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&ziinit.z_filefunc, ziinit.filestream, &ziinit.number_disk_with_CD) != ZIP_OK) + err = ZIP_ERRNO; + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry) != ZIP_OK) + err = ZIP_ERRNO; + /* total number of entries in the central directory */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &number_entry_CD) != ZIP_OK) + err = ZIP_ERRNO; + if (number_entry_CD!=number_entry) + err = ZIP_BADZIPFILE; + /* size of the central directory */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &size_central_dir) != ZIP_OK) + err = ZIP_ERRNO; + /* offset of start of central directory with respect to the starting disk number */ + if (zip64local_getLong64(&ziinit.z_filefunc, ziinit.filestream, &offset_central_dir) != ZIP_OK) + err = ZIP_ERRNO; + } + else + err = ZIP_BADZIPFILE; + } + } + + if ((err == ZIP_OK) && (central_pos 0) + { + ziinit.globalcomment = (char*)ALLOC(size_comment+1); + if (ziinit.globalcomment) + { + size_comment = ZREAD64(ziinit.z_filefunc, ziinit.filestream, ziinit.globalcomment, size_comment); + ziinit.globalcomment[size_comment] = 0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + ziinit.add_position_when_writting_offset = byte_before_the_zipfile; + + /* Store central directory in memory */ + size_central_dir_to_read = size_central_dir; + buf_size = SIZEDATA_INDATABLOCK; + buf_read = (void*)ALLOC(buf_size); + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + while ((size_central_dir_to_read > 0) && (err == ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(ziinit.z_filefunc, ziinit.filestream, buf_read, (uLong)read_this) != read_this) + err = ZIP_ERRNO; + + if (err == ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir, buf_read, (uLong)read_this); + + size_central_dir_to_read -= read_this; + } + TRYFREE(buf_read); + + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK64(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir+byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + } + + if (globalcomment) + *globalcomment = ziinit.globalcomment; +#endif + + if (err != ZIP_OK) + { +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +#endif + TRYFREE(zi); + return NULL; + } + + *zi = ziinit; + zipGoToFirstDisk((zipFile)zi); + return(zipFile)zi; +} + +extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, 0, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen4(pathname, append, 0, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, 0, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen3(const char *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, disk_size, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen3_64(const void *pathname, int append, ZPOS64_T disk_size, zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen4(pathname, append, disk_size, globalcomment, &zlib_filefunc64_32_def_fill); + } + return zipOpen4(pathname, append, disk_size, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen(const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,0,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) +{ + return zipOpen3(pathname,append,0,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, + int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment = 0; + uInt i; + int err = ZIP_OK; + ZPOS64_T size_available; + ZPOS64_T size_needed; + +#ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +#endif + + if (file == NULL) + return ZIP_PARAMERROR; + + if ((method != 0) && +#ifdef HAVE_BZIP2 + (method != Z_BZIP2ED) && +#endif + (method != Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename == NULL) + filename = "-"; + if (comment != NULL) + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.method = method; + zi->ci.compression_method = method; + zi->ci.crc32 = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.flag = flagBase; + if ((level == 8) || (level == 9)) + zi->ci.flag |= 2; + if (level == 2) + zi->ci.flag |= 4; + if (level == 1) + zi->ci.flag |= 6; + if (password != NULL) + { + zi->ci.flag |= 1; +#ifdef HAVE_AES + zi->ci.method = AES_METHOD; +#endif + } + + if (zi->disk_size > 0) + { + if ((zi->number_disk == 0) && (zi->number_entry == 0)) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)DISKHEADERMAGIC, 4); + + /* Make sure enough space available on current disk for local header */ + zipGetDiskSizeAvailable((zipFile)zi, &size_available); + size_needed = 30 + size_filename + size_extrafield_local; + if (zi->ci.zip64) + size_needed += 20; +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + size_needed += 11; +#endif + if (size_available < size_needed) + zipGoToNextDisk((zipFile)zi); + } + + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc, zi->filestream); + zi->ci.size_comment = size_comment; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global; + zi->ci.size_centralextra = size_extrafield_global; + zi->ci.size_centralextrafree = 32; /* Extra space reserved for ZIP64 extra info */ +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + zi->ci.size_centralextrafree += 11; /* Extra space reserved for AES extra info */ +#endif + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralextrafree + size_comment); + zi->ci.number_disk = zi->number_disk; + + /* Write central directory header */ + zip64local_putValue_inmemory(zi->ci.central_header, (uLong)CENTRALHEADERMAGIC, 4); + zip64local_putValue_inmemory(zi->ci.central_header+4, (uLong)versionMadeBy, 2); + zip64local_putValue_inmemory(zi->ci.central_header+6, (uLong)20, 2); + zip64local_putValue_inmemory(zi->ci.central_header+8, (uLong)zi->ci.flag, 2); + zip64local_putValue_inmemory(zi->ci.central_header+10, (uLong)zi->ci.method, 2); + zip64local_putValue_inmemory(zi->ci.central_header+12, (uLong)zi->ci.dosDate, 4); + zip64local_putValue_inmemory(zi->ci.central_header+16, (uLong)0, 4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20, (uLong)0, 4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24, (uLong)0, 4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28, (uLong)size_filename, 2); + zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)size_extrafield_global, 2); + zip64local_putValue_inmemory(zi->ci.central_header+32, (uLong)size_comment, 2); + zip64local_putValue_inmemory(zi->ci.central_header+34, (uLong)zi->ci.number_disk, 2); /*disk nm start*/ + + if (zipfi == NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)0, 2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)zipfi->internal_fa, 2); + if (zipfi == NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38, (uLong)0, 4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38, (uLong)zipfi->external_fa, 4); + if (zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42, (uLong)0xffffffff, 4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42, + (uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset, 4); + + for (i = 0; i < size_filename; i++) + zi->ci.central_header[SIZECENTRALHEADER+i] = filename[i]; + for (i = 0; i < size_extrafield_global; i++) + zi->ci.central_header[SIZECENTRALHEADER+size_filename+i] = + ((const char*)extrafield_global)[i]; + /* Store comment at the end for later repositioning */ + for (i = 0; i < size_comment; i++) + zi->ci.central_header[zi->ci.size_centralheader+ + zi->ci.size_centralextrafree+i] = comment[i]; + + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.total_compressed = 0; + zi->ci.total_uncompressed = 0; + zi->ci.pos_zip64extrainfo = 0; + + /* Write the local header */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)LOCALHEADERMAGIC, 4); + + if (err == ZIP_OK) + { + if (zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); /* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)20, 2); /* version needed to extract */ + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.flag, 2); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.method, 2); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->ci.dosDate, 4); + + /* CRC & compressed size & uncompressed size will be filled in later and rewritten later */ + + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* crc 32, unknown */ + if (err == ZIP_OK) + { + if (zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); /* compressed size, unknown */ + } + if (err == ZIP_OK) + { + if (zi->ci.zip64) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xFFFFFFFF, 4); + else /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0, 4); + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_filename, 2); + if (err == ZIP_OK) + { + ZPOS64_T size_extrafield = size_extrafield_local; + if (zi->ci.zip64) + size_extrafield += 20; +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + size_extrafield += 11; +#endif + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_extrafield,2); + } + if ((err == ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, filename, size_filename) != size_filename) + err = ZIP_ERRNO; + } + if ((err == ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + /* Write the Zip64 extended info */ + if ((err == ZIP_OK) && (zi->ci.zip64)) + { + short headerid = 1; + short datasize = 16; + ZPOS64_T compressed_size = 0; + ZPOS64_T uncompressed_size = 0; + + /* Remember position of Zip64 extended info for the local file header. + (needed when we update size after done with file) */ + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc, zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)headerid, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)datasize, 2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)uncompressed_size, 8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)compressed_size, 8); + } +#ifdef HAVE_AES + /* Write the AES extended info */ + if ((err == ZIP_OK) && (zi->ci.method == AES_METHOD)) + { + int headerid = 0x9901; + short datasize = 7; + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, headerid, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, datasize, 2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_VERSION, 2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'A', 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, 'E', 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, AES_ENCRYPTIONMODE, 1); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->ci.compression_method, 2); + } +#endif + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + + if ((err == ZIP_OK) && (!zi->ci.raw)) + { + if (method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)zi; + + if (windowBits > 0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err == Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if (method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0, 35); + if (err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + } + +#ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err == Z_OK) && ((zi->ci.flag & 1) != 0)) + { +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + unsigned char passverify[AES_PWVERIFYSIZE]; + unsigned char saltvalue[AES_MAXSALTLENGTH]; + uInt saltlength; + + if ((AES_ENCRYPTIONMODE < 1) || (AES_ENCRYPTIONMODE > 3)) + return Z_ERRNO; + + saltlength = SALT_LENGTH(AES_ENCRYPTIONMODE); + + prng_init(entropy_fun, zi->ci.aes_rng); + prng_rand(saltvalue, saltlength, zi->ci.aes_rng); + prng_end(zi->ci.aes_rng); + + fcrypt_init(AES_ENCRYPTIONMODE, password, strlen(password), saltvalue, passverify, &zi->ci.aes_ctx); + + if (ZWRITE64(zi->z_filefunc, zi->filestream, saltvalue, saltlength) != saltlength) + err = ZIP_ERRNO; + if (ZWRITE64(zi->z_filefunc, zi->filestream, passverify, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE) + err = ZIP_ERRNO; + + zi->ci.crypt_header_size = saltlength + AES_PWVERIFYSIZE + AES_AUTHCODESIZE; + } + else +#endif + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + + zi->ci.pcrc_32_tab = (const unsigned long *)get_crc_table(); + /*init_keys(password, zi->ci.keys, zi->ci.pcrc_32_tab);*/ + + sizeHead = crypthead(password, bufHead, RAND_HEAD_LEN, zi->ci.keys, zi->ci.pcrc_32_tab, crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc, zi->filestream, bufHead, sizeHead) != sizeHead) + err = ZIP_ERRNO; + } + } +#endif + + if (err == Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, + int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, + strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, + int memLevel, int strategy, const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, + strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, + int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, + uInt size_extrafield_global, const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); +} + +/* Flushes the write buffer to disk */ +local int zip64FlushWriteBuffer OF((zip64_internal* zi)); +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err = ZIP_OK; + uInt written = 0; + uInt total_written = 0; + uInt write = 0; + uInt max_write = 0; + ZPOS64_T size_available = 0; + + if ((zi->ci.flag & 1) != 0) + { +#ifndef NOCRYPT +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + fcrypt_encrypt(zi->ci.buffered_data, zi->ci.pos_in_buffered_data, &zi->ci.aes_ctx); + } + else +#endif + { + uInt i; + int t; + for (i = 0;i < zi->ci.pos_in_buffered_data; i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); + } +#endif + } + + write = zi->ci.pos_in_buffered_data; + + do + { + max_write = write; + + if (zi->disk_size > 0) + { + err = zipGetDiskSizeAvailable((zipFile)zi, &size_available); + if (err != ZIP_OK) + return err; + + if (size_available == 0) + { + err = zipGoToNextDisk((zipFile)zi); + if (err != ZIP_OK) + return err; + } + + if (size_available < (ZPOS64_T)max_write) + max_write = (uInt)size_available; + } + + written = ZWRITE64(zi->z_filefunc, zi->filestream, zi->ci.buffered_data + total_written, max_write); + + if (ZERROR64(zi->z_filefunc, zi->filestream)) + { + err = ZIP_ERRNO; + break; + } + + total_written += written; + write -= written; + } + while (write > 0); + + zi->ci.total_compressed += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if (zi->ci.compression_method == Z_BZIP2ED) + { + zi->ci.total_uncompressed += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.total_uncompressed += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip(zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err = ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32, buf, (uInt)len); + +#ifdef HAVE_BZIP2 + if ((zi->ci.compression_method == Z_BZIP2ED) && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err == BZ_RUN_OK) && (zi->ci.bstream.avail_in > 0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + else + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; + uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + + err = BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo); + } + } + + if (err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err == ZIP_OK) && (zi->ci.stream.avail_in > 0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + if (err != ZIP_OK) + break; + + if ((zi->ci.compression_method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong total_out_before = zi->ci.stream.total_out; + err = deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out -= copy_this; + zi->ci.stream.next_in += copy_this; + zi->ci.stream.next_out += copy_this; + zi->ci.stream.total_in += copy_this; + zi->ci.stream.total_out += copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + uLong i = 0; + short datasize = 0; + int err = ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if (!zi->ci.raw) + { + if (zi->ci.compression_method == Z_DEFLATED) + { + while (err == ZIP_OK) + { + uLong total_out_before; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + total_out_before = zi->ci.stream.total_out; + err = deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - total_out_before); + } + } + else if (zi->ci.compression_method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err == BZ_FINISH_OK) + { + uLong total_out_before; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + total_out_before = zi->ci.bstream.total_out_lo32; + err = BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if (err == BZ_STREAM_END) + err = Z_STREAM_END; + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - total_out_before); + } + + if (err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + } + + if (err == Z_STREAM_END) + err = ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err == ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + } + +#ifdef HAVE_AES + if (zi->ci.method == AES_METHOD) + { + unsigned char authcode[AES_AUTHCODESIZE]; + + fcrypt_end(authcode, &zi->ci.aes_ctx); + + if (ZWRITE64(zi->z_filefunc, zi->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE) + err = ZIP_ERRNO; + } +#endif + + if (!zi->ci.raw) + { + if (zi->ci.compression_method == Z_DEFLATED) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if (zi->ci.compression_method == Z_BZIP2ED) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err == ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.total_uncompressed; + } + + compressed_size = zi->ci.total_compressed; +#ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +#endif + + /* Update current item crc and sizes */ + if (compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(zi->ci.central_header+4, (uLong)45, 2); /* version made by */ + zip64local_putValue_inmemory(zi->ci.central_header+6, (uLong)45, 2); /* version needed */ + } + zip64local_putValue_inmemory(zi->ci.central_header+16, crc32, 4); /* crc */ + if (compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue, 4); /* compr size */ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size, 4); /* compr size */ + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36, (uLong)Z_ASCII, 2); /* internal file attrib */ + if (uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue, 4); /* uncompr size */ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size, 4); /* uncompr size */ + + /* Add ZIP64 extra info field for uncompressed size */ + if (uncompressed_size >= 0xffffffff) + datasize += 8; + /* Add ZIP64 extra info field for compressed size */ + if (compressed_size >= 0xffffffff) + datasize += 8; + /* Add ZIP64 extra info field for relative offset to local file header of current file */ + if (zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + /* Add Extra Information Header for 'ZIP64 information' */ + if (datasize > 0) + { + char* p = zi->ci.central_header + zi->ci.size_centralheader; + + if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) + return ZIP_BADZIPFILE; + + zip64local_putValue_inmemory(p, 0x0001, 2); + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); + p += 2; + + if (uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + if (compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + if (zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + zi->ci.size_centralextrafree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + zi->ci.size_centralextra += datasize + 4; + + zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)zi->ci.size_centralextra, 2); + } + +#ifdef HAVE_AES + /* Write the AES extended info */ + if (zi->ci.method == AES_METHOD) + { + char* p = zi->ci.central_header + zi->ci.size_centralheader; + + datasize = 7; + + if ((uLong)(datasize + 4) > zi->ci.size_centralextrafree) + return ZIP_BADZIPFILE; + + zip64local_putValue_inmemory(p, 0x9901, 2); + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); + p += 2; + zip64local_putValue_inmemory(p, AES_VERSION, 2); + p += 2; + zip64local_putValue_inmemory(p, 'A', 1); + p += 1; + zip64local_putValue_inmemory(p, 'E', 1); + p += 1; + zip64local_putValue_inmemory(p, AES_ENCRYPTIONMODE, 1); + p += 1; + zip64local_putValue_inmemory(p, zi->ci.compression_method, 2); + p += 2; + + zi->ci.size_centralextrafree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + zi->ci.size_centralextra += datasize + 4; + + zip64local_putValue_inmemory(zi->ci.central_header+30, (uLong)zi->ci.size_centralextra, 2); + } +#endif + /* Restore comment to correct position */ + for (i = 0; i < zi->ci.size_comment; i++) + zi->ci.central_header[zi->ci.size_centralheader+i] = + zi->ci.central_header[zi->ci.size_centralheader+zi->ci.size_centralextrafree+i]; + zi->ci.size_centralheader += zi->ci.size_comment; + + if (err == ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err == ZIP_OK) + { + /* Update the LocalFileHeader with the new values. */ + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + uLong cur_number_disk = zi->number_disk; + + /* Local file header is stored on previous disk, switch to make edits */ + if (zi->ci.number_disk != cur_number_disk) + err = zipGoToSpecificDisk(file, zi->ci.number_disk, 1); + + if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_local_header + 14, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream,crc32,4); /* crc 32, unknown */ + + if (uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff) + { + if (zi->ci.pos_zip64extrainfo > 0) + { + /* Update the size in the ZIP64 extended field. */ + if (ZSEEK64(zi->z_filefunc, zi->filestream, zi->ci.pos_zip64extrainfo + 4, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + + if (err == ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + if (err == ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; /* Caller passed zip64 = 0, so no room for zip64 info -> fatal */ + } + else + { + if (err == ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream,compressed_size, 4); + if (err == ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream,uncompressed_size, 4); + } + + /* Now switch back again to the disk we were on before */ + if (zi->ci.number_disk != cur_number_disk) + err = zipGoToSpecificDisk(file, cur_number_disk, 1); + + if (ZSEEK64(zi->z_filefunc, zi->filestream, cur_pos_inzip, ZLIB_FILEFUNC_SEEK_SET) != 0) + err = ZIP_ERRNO; + } + + zi->number_entry++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip(zipFile file) +{ + return zipCloseFileInZipRaw(file, 0, 0); +} + +extern int ZEXPORT zipClose(zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uInt size_global_comment = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos = 0; + uLong write = 0; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + err = zipCloseFileInZip(file); + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment == NULL) + global_comment = zi->globalcomment; +#endif + + if (zi->filestream != zi->filestream_with_CD) + { + if (ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + if (zi->disk_size > 0) + zi->number_disk_with_CD = zi->number_disk + 1; + zi->filestream = zi->filestream_with_CD; + } + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + + if (err == ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!= NULL) + { + if ((err == ZIP_OK) && (ldi->filled_in_this_block > 0)) + { + write = ZWRITE64(zi->z_filefunc, zi->filestream, ldi->data, ldi->filled_in_this_block); + if (write != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + + /* Write the ZIP64 central directory header */ + if (pos >= 0xffffffff || zi->number_entry > 0xffff) + { + ZPOS64_T zip64eocd_pos_inzip = ZTELL64(zi->z_filefunc, zi->filestream); + uLong zip64datasize = 44; + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDHEADERMAGIC, 4); + + /* size of this 'zip64 end of central directory' */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)zip64datasize, 8); + /* version made by */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); + /* version needed */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)45, 2); + /* number of this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /* number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /* total number of entries in the central dir on this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + /* total number of entries in the central dir */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + /* size of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)size_centraldir, 8); + + if (err == ZIP_OK) + { + /* offset of start of central directory with respect to the starting disk number */ + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)pos, 8); + } + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ZIP64ENDLOCHEADERMAGIC, 4); + + /* number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 4); + /*relative offset to the Zip64EndOfCentralDirectory */ + if (err == ZIP_OK) + { + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, pos, 8); + } + /* number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD+1, 4); + } + + /* Write the central directory header */ + + /* signature */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)ENDHEADERMAGIC, 4); + /* number of this disk */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); + /* number of the disk with the start of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_disk_with_CD, 2); + /* total number of entries in the central dir on this disk */ + if (err == ZIP_OK) + { + if (zi->number_entry >= 0xffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); + } + /* total number of entries in the central dir */ + if (err == ZIP_OK) + { + if (zi->number_entry >= 0xffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffff, 2); /* use value in ZIP64 record */ + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)zi->number_entry, 2); + } + /* size of the central directory */ + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_centraldir,4); + /* offset of start of central directory with respect to the starting disk number */ + if (err == ZIP_OK) + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if (pos >= 0xffffffff) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)0xffffffff, 4); + else + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)pos, 4); + } + + /* Write global comment */ + + if (global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + if (err == ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (uLong)size_global_comment, 2); + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + + if ((ZCLOSE64(zi->z_filefunc, zi->filestream) != 0) && (err == ZIP_OK)) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} diff --git a/libs/minizip/source/zipper.cpp b/libs/minizip/source/zipper.cpp index 84ce390a..7a16f768 100644 --- a/libs/minizip/source/zipper.cpp +++ b/libs/minizip/source/zipper.cpp @@ -1,316 +1,316 @@ -#include "zipper.h" -#include "defs.h" -#include "tools.h" -#include "CDirEntry.h" - -#include -#include - -namespace zipper { - - struct Zipper::Impl - { - Zipper& m_outer; - zipFile m_zf; - ourmemory_t m_zipmem; - zlib_filefunc_def m_filefunc; - - Impl(Zipper& outer) : m_outer(outer), m_zipmem(), m_filefunc() - { - m_zf = NULL; - //m_filefunc = { 0 }; - } - - bool initFile(const std::string& filename) - { - #ifdef USEWIN32IOAPI - zlib_filefunc64_def ffunc = { 0 }; - #endif - - int mode = 0; - int flags = Zipper::Append; - - /* open the zip file for output */ - if (checkFileExists(filename)) - mode = (flags & Zipper::Overwrite) ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP; - else - mode = APPEND_STATUS_CREATE; - - #ifdef USEWIN32IOAPI - fill_win32_filefunc64A(&ffunc); - m_zf = zipOpen2_64(filename.c_str(), mode, NULL, &ffunc); - #else - m_zf = zipOpen64(filename.c_str(), mode); - #endif - - return NULL != m_zf; - } - - bool initWithStream(std::iostream& stream) - { - m_zipmem.grow = 1; - - stream.seekg(0, std::ios::end); - size_t size = (size_t)stream.tellg(); - stream.seekg(0); - - if (size > 0) - { - m_zipmem.base = new char[(size_t)size]; - stream.read(m_zipmem.base, size); - } - - fill_memory_filefunc(&m_filefunc, &m_zipmem); - - return initMemory(size > 0 ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP, m_filefunc); - } - - bool initWithVector(std::vector& buffer) - { - m_zipmem.grow = 1; - - if (!buffer.empty()) - { - m_zipmem.base = new char[buffer.size()]; - memcpy(m_zipmem.base, (char*)buffer.data(), buffer.size()); - m_zipmem.size = (uLong)buffer.size(); - } - - fill_memory_filefunc(&m_filefunc, &m_zipmem); - - return initMemory(buffer.empty() ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP, m_filefunc); - } - - bool initMemory(int mode, zlib_filefunc_def& filefunc) - { - m_zf = zipOpen3("__notused__", mode, 0, 0, &filefunc); - return m_zf != NULL; - } - - bool add(std::istream& input_stream, const std::string& nameInZip, const std::string& password, int flags) - { - if (!m_zf) return false; - - int compressLevel = 0; - int zip64 = 0; - int size_buf = WRITEBUFFERSIZE; - int err = ZIP_OK; - unsigned long crcFile = 0; - - zip_fileinfo zi = { 0 }; - size_t size_read; - - std::vector buff; - buff.resize(size_buf); - - if (nameInZip.empty()) - return false; - - if (flags & Zipper::Faster) compressLevel = 1; - if (flags & Zipper::Better) compressLevel = 9; - - zip64 = (int)isLargeFile(input_stream); - if (password.empty()) - err = zipOpenNewFileInZip64(m_zf, - nameInZip.c_str(), - &zi, - NULL, - 0, - NULL, - 0, - NULL /* comment*/, - (compressLevel != 0) ? Z_DEFLATED : 0, - compressLevel, - zip64); - else - { - getFileCrc(input_stream, buff, crcFile); - err = zipOpenNewFileInZip3_64(m_zf, - nameInZip.c_str(), - &zi, - NULL, - 0, - NULL, - 0, - NULL /* comment*/, - (compressLevel != 0) ? Z_DEFLATED : 0, - compressLevel, - 0, - /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - password.c_str(), - crcFile, - zip64); - } - - if (ZIP_OK == err) - { - do { - err = ZIP_OK; - input_stream.read(buff.data(), buff.size()); - size_read = (size_t)input_stream.gcount(); - if (size_read < buff.size() && !input_stream.eof() && !input_stream.good()) - err = ZIP_ERRNO; - - if (size_read > 0) - err = zipWriteInFileInZip(this->m_zf, buff.data(), (unsigned int)size_read); - - } while ((err == ZIP_OK) && (size_read>0)); - } - else - throw EXCEPTION_CLASS(("Error adding '" + nameInZip + "' to zip").c_str()); - - if (ZIP_OK == err) - err = zipCloseFileInZip(this->m_zf); - - return ZIP_OK == err; - } - - void close() - { - if (m_zf) - zipClose(m_zf, NULL); - - if (m_zipmem.base && m_zipmem.limit > 0) - { - if (m_outer.m_usingMemoryVector) - { - m_outer.m_vecbuffer.resize(m_zipmem.limit); - m_outer.m_vecbuffer.assign(m_zipmem.base, m_zipmem.base + m_zipmem.limit); - } - - else if (m_outer.m_usingStream) - m_outer.m_obuffer.write(m_zipmem.base, m_zipmem.limit); - } - - free(m_zipmem.base); - } - }; - - /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// - - Zipper::Zipper(const std::string& zipname) - : m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_usingMemoryVector(false) - , m_usingStream(false) - , m_zipname(zipname) - , m_impl(new Impl(*this)) - { - if (!m_impl->initFile(zipname)) - throw EXCEPTION_CLASS("Error creating zip in file!"); - - m_open = true; - } - - Zipper::Zipper(const std::string& zipname, const std::string& password) - : m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_usingMemoryVector(false) - , m_usingStream(false) - , m_zipname(zipname) - , m_password(password) - , m_impl(new Impl(*this)) - { - if (!m_impl->initFile(zipname)) - throw EXCEPTION_CLASS("Error creating zip in file!"); - - m_open = true; - } - - Zipper::Zipper(std::iostream& buffer) - : m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception - , m_obuffer(buffer) - , m_usingMemoryVector(false) - , m_usingStream(true) - , m_impl(new Impl(*this)) - { - if (!m_impl->initWithStream(m_obuffer)) - throw EXCEPTION_CLASS("Error creating zip in memory!"); - - m_open = true; - } - - Zipper::Zipper(std::vector& buffer) - : m_vecbuffer(buffer) - , m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception - , m_usingMemoryVector(true) - , m_usingStream(false) - , m_impl(new Impl(*this)) - { - if (!m_impl->initWithVector(m_vecbuffer)) - throw EXCEPTION_CLASS("Error creating zip in memory!"); - - m_open = true; - } - - Zipper::~Zipper(void) - { - close(); - } - - bool Zipper::add(std::istream& source, const std::string& nameInZip, zipFlags flags) - { - return m_impl->add(source, nameInZip, "", flags); - } - - bool Zipper::add(const std::string& fileOrFolderPath, zipFlags flags) - { - if (isDirectory(fileOrFolderPath)) - { - std::string folderName = fileNameFromPath(fileOrFolderPath); - std::vector files = filesFromDirectory(fileOrFolderPath); - std::vector::iterator it = files.begin(); - for (; it != files.end(); ++it) - { - std::ifstream input(it->c_str(), std::ios::binary); - std::string nameInZip = it->substr(it->rfind(folderName + CDirEntry::Separator), it->size()); - add(input, nameInZip, flags); - input.close(); - } - } - else - { - std::ifstream input(fileOrFolderPath.c_str(), std::ios::binary); - add(input, fileNameFromPath(fileOrFolderPath), flags); - input.close(); - } - - return true; - } - - - void Zipper::open() - { - if (!m_open) - { - if (m_usingMemoryVector) - { - if (!m_impl->initWithVector(m_vecbuffer)) - throw EXCEPTION_CLASS("Error opening zip memory!"); - } - else if (m_usingStream) - { - if (!m_impl->initWithStream(m_obuffer)) - throw EXCEPTION_CLASS("Error opening zip memory!"); - } - else - { - if (!m_impl->initFile(m_zipname)) - throw EXCEPTION_CLASS("Error opening zip file!"); - } - - m_open = true; - } - } - - void Zipper::close() - { - if (m_open) - { - m_impl->close(); - m_open = false; - } - } -} +#include "zipper.h" +#include "defs.h" +#include "tools.h" +#include "CDirEntry.h" + +#include +#include + +namespace zipper { + + struct Zipper::Impl + { + Zipper& m_outer; + zipFile m_zf; + ourmemory_t m_zipmem; + zlib_filefunc_def m_filefunc; + + Impl(Zipper& outer) : m_outer(outer), m_zipmem(), m_filefunc() + { + m_zf = NULL; + //m_filefunc = { 0 }; + } + + bool initFile(const std::string& filename) + { + #ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc = { 0 }; + #endif + + int mode = 0; + int flags = Zipper::Append; + + /* open the zip file for output */ + if (checkFileExists(filename)) + mode = (flags & Zipper::Overwrite) ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP; + else + mode = APPEND_STATUS_CREATE; + + #ifdef USEWIN32IOAPI + fill_win32_filefunc64A(&ffunc); + m_zf = zipOpen2_64(filename.c_str(), mode, NULL, &ffunc); + #else + m_zf = zipOpen64(filename.c_str(), mode); + #endif + + return NULL != m_zf; + } + + bool initWithStream(std::iostream& stream) + { + m_zipmem.grow = 1; + + stream.seekg(0, std::ios::end); + size_t size = (size_t)stream.tellg(); + stream.seekg(0); + + if (size > 0) + { + m_zipmem.base = new char[(size_t)size]; + stream.read(m_zipmem.base, size); + } + + fill_memory_filefunc(&m_filefunc, &m_zipmem); + + return initMemory(size > 0 ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP, m_filefunc); + } + + bool initWithVector(std::vector& buffer) + { + m_zipmem.grow = 1; + + if (!buffer.empty()) + { + m_zipmem.base = new char[buffer.size()]; + memcpy(m_zipmem.base, (char*)buffer.data(), buffer.size()); + m_zipmem.size = (uLong)buffer.size(); + } + + fill_memory_filefunc(&m_filefunc, &m_zipmem); + + return initMemory(buffer.empty() ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP, m_filefunc); + } + + bool initMemory(int mode, zlib_filefunc_def& filefunc) + { + m_zf = zipOpen3("__notused__", mode, 0, 0, &filefunc); + return m_zf != NULL; + } + + bool add(std::istream& input_stream, const std::string& nameInZip, const std::string& password, int flags) + { + if (!m_zf) return false; + + int compressLevel = 0; + int zip64 = 0; + int size_buf = WRITEBUFFERSIZE; + int err = ZIP_OK; + unsigned long crcFile = 0; + + zip_fileinfo zi = { 0 }; + size_t size_read; + + std::vector buff; + buff.resize(size_buf); + + if (nameInZip.empty()) + return false; + + if (flags & Zipper::Faster) compressLevel = 1; + if (flags & Zipper::Better) compressLevel = 9; + + zip64 = (int)isLargeFile(input_stream); + if (password.empty()) + err = zipOpenNewFileInZip64(m_zf, + nameInZip.c_str(), + &zi, + NULL, + 0, + NULL, + 0, + NULL /* comment*/, + (compressLevel != 0) ? Z_DEFLATED : 0, + compressLevel, + zip64); + else + { + getFileCrc(input_stream, buff, crcFile); + err = zipOpenNewFileInZip3_64(m_zf, + nameInZip.c_str(), + &zi, + NULL, + 0, + NULL, + 0, + NULL /* comment*/, + (compressLevel != 0) ? Z_DEFLATED : 0, + compressLevel, + 0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password.c_str(), + crcFile, + zip64); + } + + if (ZIP_OK == err) + { + do { + err = ZIP_OK; + input_stream.read(buff.data(), buff.size()); + size_read = (size_t)input_stream.gcount(); + if (size_read < buff.size() && !input_stream.eof() && !input_stream.good()) + err = ZIP_ERRNO; + + if (size_read > 0) + err = zipWriteInFileInZip(this->m_zf, buff.data(), (unsigned int)size_read); + + } while ((err == ZIP_OK) && (size_read>0)); + } + else + throw EXCEPTION_CLASS(("Error adding '" + nameInZip + "' to zip").c_str()); + + if (ZIP_OK == err) + err = zipCloseFileInZip(this->m_zf); + + return ZIP_OK == err; + } + + void close() + { + if (m_zf) + zipClose(m_zf, NULL); + + if (m_zipmem.base && m_zipmem.limit > 0) + { + if (m_outer.m_usingMemoryVector) + { + m_outer.m_vecbuffer.resize(m_zipmem.limit); + m_outer.m_vecbuffer.assign(m_zipmem.base, m_zipmem.base + m_zipmem.limit); + } + + else if (m_outer.m_usingStream) + m_outer.m_obuffer.write(m_zipmem.base, m_zipmem.limit); + } + + free(m_zipmem.base); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + + Zipper::Zipper(const std::string& zipname) + : m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_usingMemoryVector(false) + , m_usingStream(false) + , m_zipname(zipname) + , m_impl(new Impl(*this)) + { + if (!m_impl->initFile(zipname)) + throw EXCEPTION_CLASS("Error creating zip in file!"); + + m_open = true; + } + + Zipper::Zipper(const std::string& zipname, const std::string& password) + : m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_usingMemoryVector(false) + , m_usingStream(false) + , m_zipname(zipname) + , m_password(password) + , m_impl(new Impl(*this)) + { + if (!m_impl->initFile(zipname)) + throw EXCEPTION_CLASS("Error creating zip in file!"); + + m_open = true; + } + + Zipper::Zipper(std::iostream& buffer) + : m_vecbuffer(*(new std::vector())) //not used but using local variable throws exception + , m_obuffer(buffer) + , m_usingMemoryVector(false) + , m_usingStream(true) + , m_impl(new Impl(*this)) + { + if (!m_impl->initWithStream(m_obuffer)) + throw EXCEPTION_CLASS("Error creating zip in memory!"); + + m_open = true; + } + + Zipper::Zipper(std::vector& buffer) + : m_vecbuffer(buffer) + , m_obuffer(*(new std::stringstream())) //not used but using local variable throws exception + , m_usingMemoryVector(true) + , m_usingStream(false) + , m_impl(new Impl(*this)) + { + if (!m_impl->initWithVector(m_vecbuffer)) + throw EXCEPTION_CLASS("Error creating zip in memory!"); + + m_open = true; + } + + Zipper::~Zipper(void) + { + close(); + } + + bool Zipper::add(std::istream& source, const std::string& nameInZip, zipFlags flags) + { + return m_impl->add(source, nameInZip, "", flags); + } + + bool Zipper::add(const std::string& fileOrFolderPath, zipFlags flags) + { + if (isDirectory(fileOrFolderPath)) + { + std::string folderName = fileNameFromPath(fileOrFolderPath); + std::vector files = filesFromDirectory(fileOrFolderPath); + std::vector::iterator it = files.begin(); + for (; it != files.end(); ++it) + { + std::ifstream input(it->c_str(), std::ios::binary); + std::string nameInZip = it->substr(it->rfind(folderName + CDirEntry::Separator), it->size()); + add(input, nameInZip, flags); + input.close(); + } + } + else + { + std::ifstream input(fileOrFolderPath.c_str(), std::ios::binary); + add(input, fileNameFromPath(fileOrFolderPath), flags); + input.close(); + } + + return true; + } + + + void Zipper::open() + { + if (!m_open) + { + if (m_usingMemoryVector) + { + if (!m_impl->initWithVector(m_vecbuffer)) + throw EXCEPTION_CLASS("Error opening zip memory!"); + } + else if (m_usingStream) + { + if (!m_impl->initWithStream(m_obuffer)) + throw EXCEPTION_CLASS("Error opening zip memory!"); + } + else + { + if (!m_impl->initFile(m_zipname)) + throw EXCEPTION_CLASS("Error opening zip file!"); + } + + m_open = true; + } + } + + void Zipper::close() + { + if (m_open) + { + m_impl->close(); + m_open = false; + } + } +} diff --git a/libs/nanojpeg/include/nanojpeg.h b/libs/nanojpeg/include/nanojpeg.h index cf913b89..2f2b3256 100644 --- a/libs/nanojpeg/include/nanojpeg.h +++ b/libs/nanojpeg/include/nanojpeg.h @@ -1,61 +1,61 @@ -#ifndef _NANOJPEG_H -#define _NANOJPEG_H - -// nj_result_t: Result codes for njDecode(). -typedef enum _nj_result { - NJ_OK = 0, // no error, decoding successful - NJ_NO_JPEG, // not a JPEG file - NJ_UNSUPPORTED, // unsupported format - NJ_OUT_OF_MEM, // out of memory - NJ_INTERNAL_ERR, // internal error - NJ_SYNTAX_ERROR, // syntax error - __NJ_FINISHED, // used internally, will never be reported -} nj_result_t; - -// njInit: Initialize NanoJPEG. -// For safety reasons, this should be called at least one time before using -// using any of the other NanoJPEG functions. -void njInit(void); - -// njDecode: Decode a JPEG image. -// Decodes a memory dump of a JPEG file into internal buffers. -// Parameters: -// jpeg = The pointer to the memory dump. -// size = The size of the JPEG file. -// Return value: The error code in case of failure, or NJ_OK (zero) on success. -nj_result_t njDecode(const void* jpeg, const int size); - -// njGetWidth: Return the width (in pixels) of the most recently decoded -// image. If njDecode() failed, the result of njGetWidth() is undefined. -int njGetWidth(void); - -// njGetHeight: Return the height (in pixels) of the most recently decoded -// image. If njDecode() failed, the result of njGetHeight() is undefined. -int njGetHeight(void); - -// njIsColor: Return 1 if the most recently decoded image is a color image -// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result -// of njGetWidth() is undefined. -int njIsColor(void); - -// njGetImage: Returns the decoded image data. -// Returns a pointer to the most recently image. The memory layout it byte- -// oriented, top-down, without any padding between lines. Pixels of color -// images will be stored as three consecutive bytes for the red, green and -// blue channels. This data format is thus compatible with the PGM or PPM -// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8. -// If njDecode() failed, the result of njGetImage() is undefined. -unsigned char* njGetImage(void); - -// njGetImageSize: Returns the size (in bytes) of the image data returned -// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is -// undefined. -int njGetImageSize(void); - -// njDone: Uninitialize NanoJPEG. -// Resets NanoJPEG's internal state and frees all memory that has been -// allocated at run-time by NanoJPEG. It is still possible to decode another -// image after a njDone() call. -void njDone(void); - -#endif//_NANOJPEG_H +#ifndef _NANOJPEG_H +#define _NANOJPEG_H + +// nj_result_t: Result codes for njDecode(). +typedef enum _nj_result { + NJ_OK = 0, // no error, decoding successful + NJ_NO_JPEG, // not a JPEG file + NJ_UNSUPPORTED, // unsupported format + NJ_OUT_OF_MEM, // out of memory + NJ_INTERNAL_ERR, // internal error + NJ_SYNTAX_ERROR, // syntax error + __NJ_FINISHED, // used internally, will never be reported +} nj_result_t; + +// njInit: Initialize NanoJPEG. +// For safety reasons, this should be called at least one time before using +// using any of the other NanoJPEG functions. +void njInit(void); + +// njDecode: Decode a JPEG image. +// Decodes a memory dump of a JPEG file into internal buffers. +// Parameters: +// jpeg = The pointer to the memory dump. +// size = The size of the JPEG file. +// Return value: The error code in case of failure, or NJ_OK (zero) on success. +nj_result_t njDecode(const void* jpeg, const int size); + +// njGetWidth: Return the width (in pixels) of the most recently decoded +// image. If njDecode() failed, the result of njGetWidth() is undefined. +int njGetWidth(void); + +// njGetHeight: Return the height (in pixels) of the most recently decoded +// image. If njDecode() failed, the result of njGetHeight() is undefined. +int njGetHeight(void); + +// njIsColor: Return 1 if the most recently decoded image is a color image +// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result +// of njGetWidth() is undefined. +int njIsColor(void); + +// njGetImage: Returns the decoded image data. +// Returns a pointer to the most recently image. The memory layout it byte- +// oriented, top-down, without any padding between lines. Pixels of color +// images will be stored as three consecutive bytes for the red, green and +// blue channels. This data format is thus compatible with the PGM or PPM +// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8. +// If njDecode() failed, the result of njGetImage() is undefined. +unsigned char* njGetImage(void); + +// njGetImageSize: Returns the size (in bytes) of the image data returned +// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is +// undefined. +int njGetImageSize(void); + +// njDone: Uninitialize NanoJPEG. +// Resets NanoJPEG's internal state and frees all memory that has been +// allocated at run-time by NanoJPEG. It is still possible to decode another +// image after a njDone() call. +void njDone(void); + +#endif//_NANOJPEG_H diff --git a/libs/nanojpeg/source/nanojpeg.c b/libs/nanojpeg/source/nanojpeg.c index abfac49b..6bf6397d 100644 --- a/libs/nanojpeg/source/nanojpeg.c +++ b/libs/nanojpeg/source/nanojpeg.c @@ -1,916 +1,916 @@ -// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder -// version 1.3.5 (2016-11-14) -// Copyright (c) 2009-2016 Martin J. Fiedler -// published under the terms of the MIT license -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - - -/////////////////////////////////////////////////////////////////////////////// -// DOCUMENTATION SECTION // -// read this if you want to know what this is all about // -/////////////////////////////////////////////////////////////////////////////// - -// INTRODUCTION -// ============ -// -// This is a minimal decoder for baseline JPEG images. It accepts memory dumps -// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit -// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files -// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are -// not supported. All YCbCr subsampling schemes with power-of-two ratios are -// supported, as are restart intervals. Progressive or lossless JPEG is not -// supported. -// Summed up, NanoJPEG should be able to decode all images from digital cameras -// and most common forms of other non-progressive JPEG images. -// The decoder is not optimized for speed, it's optimized for simplicity and -// small code. Image quality should be at a reasonable level. A bicubic chroma -// upsampling filter ensures that subsampled YCbCr images are rendered in -// decent quality. The decoder is not meant to deal with broken JPEG files in -// a graceful manner; if anything is wrong with the bitstream, decoding will -// simply fail. -// The code should work with every modern C compiler without problems and -// should not emit any warnings. It uses only (at least) 32-bit integer -// arithmetic and is supposed to be endianness independent and 64-bit clean. -// However, it is not thread-safe. - - -// COMPILE-TIME CONFIGURATION -// ========================== -// -// The following aspects of NanoJPEG can be controlled with preprocessor -// defines: -// -// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example -// program. -// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header -// file for NanoJPEG. Example: -// #define _NJ_INCLUDE_HEADER_ONLY -// #include "nanojpeg.c" -// int main(void) { -// njInit(); -// // your code here -// njDone(); -// } -// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy() -// functions from the standard C library (default). -// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode, -// external functions njAlloc(), njFreeMem(), -// njFillMem() and njCopyMem() need to be defined -// and implemented somewhere. -// NJ_USE_WIN32=0 = Normal mode (default). -// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and -// NJ_USE_LIBC=0, NanoJPEG will use its own -// implementations of the required C library -// functions (default if compiling with MSVC and -// NJ_USE_LIBC=0). -// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter -// (default). -// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling -// (bad quality, but faster and less code). - - -// API -// === -// -// For API documentation, read the "header section" below. - - -// EXAMPLE -// ======= -// -// A few pages below, you can find an example program that uses NanoJPEG to -// convert JPEG files into PGM or PPM. To compile it, use something like -// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c -// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :) -// The only thing you might need is -Wno-shift-negative-value, because this -// code relies on the target machine using two's complement arithmetic, but -// the C standard does not, even though *any* practically useful machine -// nowadays uses two's complement. - - -/////////////////////////////////////////////////////////////////////////////// -// HEADER SECTION // -// copy and pase this into nanojpeg.h if you want // -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _NANOJPEG_H -#define _NANOJPEG_H - -// nj_result_t: Result codes for njDecode(). -typedef enum _nj_result { - NJ_OK = 0, // no error, decoding successful - NJ_NO_JPEG, // not a JPEG file - NJ_UNSUPPORTED, // unsupported format - NJ_OUT_OF_MEM, // out of memory - NJ_INTERNAL_ERR, // internal error - NJ_SYNTAX_ERROR, // syntax error - __NJ_FINISHED, // used internally, will never be reported -} nj_result_t; - -// njInit: Initialize NanoJPEG. -// For safety reasons, this should be called at least one time before using -// using any of the other NanoJPEG functions. -void njInit(void); - -// njDecode: Decode a JPEG image. -// Decodes a memory dump of a JPEG file into internal buffers. -// Parameters: -// jpeg = The pointer to the memory dump. -// size = The size of the JPEG file. -// Return value: The error code in case of failure, or NJ_OK (zero) on success. -nj_result_t njDecode(const void* jpeg, const int size); - -// njGetWidth: Return the width (in pixels) of the most recently decoded -// image. If njDecode() failed, the result of njGetWidth() is undefined. -int njGetWidth(void); - -// njGetHeight: Return the height (in pixels) of the most recently decoded -// image. If njDecode() failed, the result of njGetHeight() is undefined. -int njGetHeight(void); - -// njIsColor: Return 1 if the most recently decoded image is a color image -// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result -// of njGetWidth() is undefined. -int njIsColor(void); - -// njGetImage: Returns the decoded image data. -// Returns a pointer to the most recently image. The memory layout it byte- -// oriented, top-down, without any padding between lines. Pixels of color -// images will be stored as three consecutive bytes for the red, green and -// blue channels. This data format is thus compatible with the PGM or PPM -// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8. -// If njDecode() failed, the result of njGetImage() is undefined. -unsigned char* njGetImage(void); - -// njGetImageSize: Returns the size (in bytes) of the image data returned -// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is -// undefined. -int njGetImageSize(void); - -// njDone: Uninitialize NanoJPEG. -// Resets NanoJPEG's internal state and frees all memory that has been -// allocated at run-time by NanoJPEG. It is still possible to decode another -// image after a njDone() call. -void njDone(void); - -#endif//_NANOJPEG_H - - -/////////////////////////////////////////////////////////////////////////////// -// CONFIGURATION SECTION // -// adjust the default settings for the NJ_ defines here // -/////////////////////////////////////////////////////////////////////////////// - -#ifndef NJ_USE_LIBC - #define NJ_USE_LIBC 1 -#endif - -#ifndef NJ_USE_WIN32 - #ifdef _MSC_VER - #define NJ_USE_WIN32 (!NJ_USE_LIBC) - #else - #define NJ_USE_WIN32 0 - #endif -#endif - -#ifndef NJ_CHROMA_FILTER - #define NJ_CHROMA_FILTER 1 -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// EXAMPLE PROGRAM // -// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) // -/////////////////////////////////////////////////////////////////////////////// - -#ifdef _NJ_EXAMPLE_PROGRAM - -#include -#include -#include - -int main(int argc, char* argv[]) { - int size; - char *buf; - FILE *f; - - if (argc < 2) { - printf("Usage: %s []\n", argv[0]); - return 2; - } - f = fopen(argv[1], "rb"); - if (!f) { - printf("Error opening the input file.\n"); - return 1; - } - fseek(f, 0, SEEK_END); - size = (int) ftell(f); - buf = (char*) malloc(size); - fseek(f, 0, SEEK_SET); - size = (int) fread(buf, 1, size, f); - fclose(f); - - njInit(); - if (njDecode(buf, size)) { - free((void*)buf); - printf("Error decoding the input file.\n"); - return 1; - } - free((void*)buf); - - f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb"); - if (!f) { - printf("Error opening the output file.\n"); - return 1; - } - fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight()); - fwrite(njGetImage(), 1, njGetImageSize(), f); - fclose(f); - njDone(); - return 0; -} - -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// IMPLEMENTATION SECTION // -// you may stop reading here // -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _NJ_INCLUDE_HEADER_ONLY - -#ifdef _MSC_VER - #define NJ_INLINE static __inline - #define NJ_FORCE_INLINE static __forceinline -#else - #define NJ_INLINE static inline - #define NJ_FORCE_INLINE static inline -#endif - -#if NJ_USE_LIBC - #include - #include - #define njAllocMem malloc - #define njFreeMem free - #define njFillMem memset - #define njCopyMem memcpy -#elif NJ_USE_WIN32 - #include - #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size))) - #define njFreeMem(block) ((void) LocalFree((HLOCAL) block)) - NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm { - mov edi, block - mov al, value - mov ecx, count - rep stosb - } } - NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm { - mov edi, dest - mov esi, src - mov ecx, count - rep movsb - } } -#else - extern void* njAllocMem(int size); - extern void njFreeMem(void* block); - extern void njFillMem(void* block, unsigned char byte, int size); - extern void njCopyMem(void* dest, const void* src, int size); -#endif - -typedef struct _nj_code { - unsigned char bits, code; -} nj_vlc_code_t; - -typedef struct _nj_cmp { - int cid; - int ssx, ssy; - int width, height; - int stride; - int qtsel; - int actabsel, dctabsel; - int dcpred; - unsigned char *pixels; -} nj_component_t; - -typedef struct _nj_ctx { - nj_result_t error; - const unsigned char *pos; - int size; - int length; - int width, height; - int mbwidth, mbheight; - int mbsizex, mbsizey; - int ncomp; - nj_component_t comp[3]; - int qtused, qtavail; - unsigned char qtab[4][64]; - nj_vlc_code_t vlctab[4][65536]; - int buf, bufbits; - int block[64]; - int rstinterval; - unsigned char *rgb; -} nj_context_t; - -static nj_context_t nj; - -static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, -11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, -42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, -38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; - -NJ_FORCE_INLINE unsigned char njClip(const int x) { - return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x); -} - -#define W1 2841 -#define W2 2676 -#define W3 2408 -#define W5 1609 -#define W6 1108 -#define W7 565 - -NJ_INLINE void njRowIDCT(int* blk) { - int x0, x1, x2, x3, x4, x5, x6, x7, x8; - if (!((x1 = blk[4] << 11) - | (x2 = blk[6]) - | (x3 = blk[2]) - | (x4 = blk[1]) - | (x5 = blk[7]) - | (x6 = blk[5]) - | (x7 = blk[3]))) - { - blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3; - return; - } - x0 = (blk[0] << 11) + 128; - x8 = W7 * (x4 + x5); - x4 = x8 + (W1 - W7) * x4; - x5 = x8 - (W1 + W7) * x5; - x8 = W3 * (x6 + x7); - x6 = x8 - (W3 - W5) * x6; - x7 = x8 - (W3 + W5) * x7; - x8 = x0 + x1; - x0 -= x1; - x1 = W6 * (x3 + x2); - x2 = x1 - (W2 + W6) * x2; - x3 = x1 + (W2 - W6) * x3; - x1 = x4 + x6; - x4 -= x6; - x6 = x5 + x7; - x5 -= x7; - x7 = x8 + x3; - x8 -= x3; - x3 = x0 + x2; - x0 -= x2; - x2 = (181 * (x4 + x5) + 128) >> 8; - x4 = (181 * (x4 - x5) + 128) >> 8; - blk[0] = (x7 + x1) >> 8; - blk[1] = (x3 + x2) >> 8; - blk[2] = (x0 + x4) >> 8; - blk[3] = (x8 + x6) >> 8; - blk[4] = (x8 - x6) >> 8; - blk[5] = (x0 - x4) >> 8; - blk[6] = (x3 - x2) >> 8; - blk[7] = (x7 - x1) >> 8; -} - -NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) { - int x0, x1, x2, x3, x4, x5, x6, x7, x8; - if (!((x1 = blk[8*4] << 8) - | (x2 = blk[8*6]) - | (x3 = blk[8*2]) - | (x4 = blk[8*1]) - | (x5 = blk[8*7]) - | (x6 = blk[8*5]) - | (x7 = blk[8*3]))) - { - x1 = njClip(((blk[0] + 32) >> 6) + 128); - for (x0 = 8; x0; --x0) { - *out = (unsigned char) x1; - out += stride; - } - return; - } - x0 = (blk[0] << 8) + 8192; - x8 = W7 * (x4 + x5) + 4; - x4 = (x8 + (W1 - W7) * x4) >> 3; - x5 = (x8 - (W1 + W7) * x5) >> 3; - x8 = W3 * (x6 + x7) + 4; - x6 = (x8 - (W3 - W5) * x6) >> 3; - x7 = (x8 - (W3 + W5) * x7) >> 3; - x8 = x0 + x1; - x0 -= x1; - x1 = W6 * (x3 + x2) + 4; - x2 = (x1 - (W2 + W6) * x2) >> 3; - x3 = (x1 + (W2 - W6) * x3) >> 3; - x1 = x4 + x6; - x4 -= x6; - x6 = x5 + x7; - x5 -= x7; - x7 = x8 + x3; - x8 -= x3; - x3 = x0 + x2; - x0 -= x2; - x2 = (181 * (x4 + x5) + 128) >> 8; - x4 = (181 * (x4 - x5) + 128) >> 8; - *out = njClip(((x7 + x1) >> 14) + 128); out += stride; - *out = njClip(((x3 + x2) >> 14) + 128); out += stride; - *out = njClip(((x0 + x4) >> 14) + 128); out += stride; - *out = njClip(((x8 + x6) >> 14) + 128); out += stride; - *out = njClip(((x8 - x6) >> 14) + 128); out += stride; - *out = njClip(((x0 - x4) >> 14) + 128); out += stride; - *out = njClip(((x3 - x2) >> 14) + 128); out += stride; - *out = njClip(((x7 - x1) >> 14) + 128); -} - -#define njThrow(e) do { nj.error = e; return; } while (0) -#define njCheckError() do { if (nj.error) return; } while (0) - -static int njShowBits(int bits) { - unsigned char newbyte; - if (!bits) return 0; - while (nj.bufbits < bits) { - if (nj.size <= 0) { - nj.buf = (nj.buf << 8) | 0xFF; - nj.bufbits += 8; - continue; - } - newbyte = *nj.pos++; - nj.size--; - nj.bufbits += 8; - nj.buf = (nj.buf << 8) | newbyte; - if (newbyte == 0xFF) { - if (nj.size) { - unsigned char marker = *nj.pos++; - nj.size--; - switch (marker) { - case 0x00: - case 0xFF: - break; - case 0xD9: nj.size = 0; break; - default: - if ((marker & 0xF8) != 0xD0) - nj.error = NJ_SYNTAX_ERROR; - else { - nj.buf = (nj.buf << 8) | marker; - nj.bufbits += 8; - } - } - } else - nj.error = NJ_SYNTAX_ERROR; - } - } - return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1); -} - -NJ_INLINE void njSkipBits(int bits) { - if (nj.bufbits < bits) - (void) njShowBits(bits); - nj.bufbits -= bits; -} - -NJ_INLINE int njGetBits(int bits) { - int res = njShowBits(bits); - njSkipBits(bits); - return res; -} - -NJ_INLINE void njByteAlign(void) { - nj.bufbits &= 0xF8; -} - -static void njSkip(int count) { - nj.pos += count; - nj.size -= count; - nj.length -= count; - if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR; -} - -NJ_INLINE unsigned short njDecode16(const unsigned char *pos) { - return (pos[0] << 8) | pos[1]; -} - -static void njDecodeLength(void) { - if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR); - nj.length = njDecode16(nj.pos); - if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR); - njSkip(2); -} - -NJ_INLINE void njSkipMarker(void) { - njDecodeLength(); - njSkip(nj.length); -} - -NJ_INLINE void njDecodeSOF(void) { - int i, ssxmax = 0, ssymax = 0; - nj_component_t* c; - njDecodeLength(); - njCheckError(); - if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR); - if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED); - nj.height = njDecode16(nj.pos+1); - nj.width = njDecode16(nj.pos+3); - if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR); - nj.ncomp = nj.pos[5]; - njSkip(6); - switch (nj.ncomp) { - case 1: - case 3: - break; - default: - njThrow(NJ_UNSUPPORTED); - } - if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR); - for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { - c->cid = nj.pos[0]; - if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR); - if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two - if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR); - if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two - if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR); - njSkip(3); - nj.qtused |= 1 << c->qtsel; - if (c->ssx > ssxmax) ssxmax = c->ssx; - if (c->ssy > ssymax) ssymax = c->ssy; - } - if (nj.ncomp == 1) { - c = nj.comp; - c->ssx = c->ssy = ssxmax = ssymax = 1; - } - nj.mbsizex = ssxmax << 3; - nj.mbsizey = ssymax << 3; - nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex; - nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey; - for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { - c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax; - c->height = (nj.height * c->ssy + ssymax - 1) / ssymax; - c->stride = nj.mbwidth * c->ssx << 3; - if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED); - if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM); - } - if (nj.ncomp == 3) { - nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp); - if (!nj.rgb) njThrow(NJ_OUT_OF_MEM); - } - njSkip(nj.length); -} - -NJ_INLINE void njDecodeDHT(void) { - int codelen, currcnt, remain, spread, i, j; - nj_vlc_code_t *vlc; - static unsigned char counts[16]; - njDecodeLength(); - njCheckError(); - while (nj.length >= 17) { - i = nj.pos[0]; - if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR); - if (i & 0x02) njThrow(NJ_UNSUPPORTED); - i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value - for (codelen = 1; codelen <= 16; ++codelen) - counts[codelen - 1] = nj.pos[codelen]; - njSkip(17); - vlc = &nj.vlctab[i][0]; - remain = spread = 65536; - for (codelen = 1; codelen <= 16; ++codelen) { - spread >>= 1; - currcnt = counts[codelen - 1]; - if (!currcnt) continue; - if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR); - remain -= currcnt << (16 - codelen); - if (remain < 0) njThrow(NJ_SYNTAX_ERROR); - for (i = 0; i < currcnt; ++i) { - register unsigned char code = nj.pos[i]; - for (j = spread; j; --j) { - vlc->bits = (unsigned char) codelen; - vlc->code = code; - ++vlc; - } - } - njSkip(currcnt); - } - while (remain--) { - vlc->bits = 0; - ++vlc; - } - } - if (nj.length) njThrow(NJ_SYNTAX_ERROR); -} - -NJ_INLINE void njDecodeDQT(void) { - int i; - unsigned char *t; - njDecodeLength(); - njCheckError(); - while (nj.length >= 65) { - i = nj.pos[0]; - if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR); - nj.qtavail |= 1 << i; - t = &nj.qtab[i][0]; - for (i = 0; i < 64; ++i) - t[i] = nj.pos[i + 1]; - njSkip(65); - } - if (nj.length) njThrow(NJ_SYNTAX_ERROR); -} - -NJ_INLINE void njDecodeDRI(void) { - njDecodeLength(); - njCheckError(); - if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR); - nj.rstinterval = njDecode16(nj.pos); - njSkip(nj.length); -} - -static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) { - int value = njShowBits(16); - int bits = vlc[value].bits; - if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; } - njSkipBits(bits); - value = vlc[value].code; - if (code) *code = (unsigned char) value; - bits = value & 15; - if (!bits) return 0; - value = njGetBits(bits); - if (value < (1 << (bits - 1))) - value += ((-1) << bits) + 1; - return value; -} - -NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) { - unsigned char code = 0; - int value, coef = 0; - njFillMem(nj.block, 0, sizeof(nj.block)); - c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL); - nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0]; - do { - value = njGetVLC(&nj.vlctab[c->actabsel][0], &code); - if (!code) break; // EOB - if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR); - coef += (code >> 4) + 1; - if (coef > 63) njThrow(NJ_SYNTAX_ERROR); - nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef]; - } while (coef < 63); - for (coef = 0; coef < 64; coef += 8) - njRowIDCT(&nj.block[coef]); - for (coef = 0; coef < 8; ++coef) - njColIDCT(&nj.block[coef], &out[coef], c->stride); -} - -NJ_INLINE void njDecodeScan(void) { - int i, mbx, mby, sbx, sby; - int rstcount = nj.rstinterval, nextrst = 0; - nj_component_t* c; - njDecodeLength(); - njCheckError(); - if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR); - if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED); - njSkip(1); - for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { - if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR); - if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR); - c->dctabsel = nj.pos[1] >> 4; - c->actabsel = (nj.pos[1] & 1) | 2; - njSkip(2); - } - if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED); - njSkip(nj.length); - for (mbx = mby = 0;;) { - for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) - for (sby = 0; sby < c->ssy; ++sby) - for (sbx = 0; sbx < c->ssx; ++sbx) { - njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]); - njCheckError(); - } - if (++mbx >= nj.mbwidth) { - mbx = 0; - if (++mby >= nj.mbheight) break; - } - if (nj.rstinterval && !(--rstcount)) { - njByteAlign(); - i = njGetBits(16); - if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR); - nextrst = (nextrst + 1) & 7; - rstcount = nj.rstinterval; - for (i = 0; i < 3; ++i) - nj.comp[i].dcpred = 0; - } - } - nj.error = __NJ_FINISHED; -} - -#if NJ_CHROMA_FILTER - -#define CF4A (-9) -#define CF4B (111) -#define CF4C (29) -#define CF4D (-3) -#define CF3A (28) -#define CF3B (109) -#define CF3C (-9) -#define CF3X (104) -#define CF3Y (27) -#define CF3Z (-3) -#define CF2A (139) -#define CF2B (-11) -#define CF(x) njClip(((x) + 64) >> 7) - -NJ_INLINE void njUpsampleH(nj_component_t* c) { - const int xmax = c->width - 3; - unsigned char *out, *lin, *lout; - int x, y; - out = (unsigned char*) njAllocMem((c->width * c->height) << 1); - if (!out) njThrow(NJ_OUT_OF_MEM); - lin = c->pixels; - lout = out; - for (y = c->height; y; --y) { - lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]); - lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]); - lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]); - for (x = 0; x < xmax; ++x) { - lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]); - lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]); - } - lin += c->stride; - lout += c->width << 1; - lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]); - lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]); - lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]); - } - c->width <<= 1; - c->stride = c->width; - njFreeMem((void*)c->pixels); - c->pixels = out; -} - -NJ_INLINE void njUpsampleV(nj_component_t* c) { - const int w = c->width, s1 = c->stride, s2 = s1 + s1; - unsigned char *out, *cin, *cout; - int x, y; - out = (unsigned char*) njAllocMem((c->width * c->height) << 1); - if (!out) njThrow(NJ_OUT_OF_MEM); - for (x = 0; x < w; ++x) { - cin = &c->pixels[x]; - cout = &out[x]; - *cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w; - *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w; - *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w; - cin += s1; - for (y = c->height - 3; y; --y) { - *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w; - *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w; - cin += s1; - } - cin += s1; - *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w; - *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w; - *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]); - } - c->height <<= 1; - c->stride = c->width; - njFreeMem((void*) c->pixels); - c->pixels = out; -} - -#else - -NJ_INLINE void njUpsample(nj_component_t* c) { - int x, y, xshift = 0, yshift = 0; - unsigned char *out, *lin, *lout; - while (c->width < nj.width) { c->width <<= 1; ++xshift; } - while (c->height < nj.height) { c->height <<= 1; ++yshift; } - out = (unsigned char*) njAllocMem(c->width * c->height); - if (!out) njThrow(NJ_OUT_OF_MEM); - lin = c->pixels; - lout = out; - for (y = 0; y < c->height; ++y) { - lin = &c->pixels[(y >> yshift) * c->stride]; - for (x = 0; x < c->width; ++x) - lout[x] = lin[x >> xshift]; - lout += c->width; - } - c->stride = c->width; - njFreeMem((void*) c->pixels); - c->pixels = out; -} - -#endif - -NJ_INLINE void njConvert(void) { - int i; - nj_component_t* c; - for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { - #if NJ_CHROMA_FILTER - while ((c->width < nj.width) || (c->height < nj.height)) { - if (c->width < nj.width) njUpsampleH(c); - njCheckError(); - if (c->height < nj.height) njUpsampleV(c); - njCheckError(); - } - #else - if ((c->width < nj.width) || (c->height < nj.height)) - njUpsample(c); - #endif - if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR); - } - if (nj.ncomp == 3) { - // convert to RGB - int x, yy; - unsigned char *prgb = nj.rgb; - const unsigned char *py = nj.comp[0].pixels; - const unsigned char *pcb = nj.comp[1].pixels; - const unsigned char *pcr = nj.comp[2].pixels; - for (yy = nj.height; yy; --yy) { - for (x = 0; x < nj.width; ++x) { - register int y = py[x] << 8; - register int cb = pcb[x] - 128; - register int cr = pcr[x] - 128; - *prgb++ = njClip((y + 359 * cr + 128) >> 8); - *prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8); - *prgb++ = njClip((y + 454 * cb + 128) >> 8); - } - py += nj.comp[0].stride; - pcb += nj.comp[1].stride; - pcr += nj.comp[2].stride; - } - } else if (nj.comp[0].width != nj.comp[0].stride) { - // grayscale -> only remove stride - unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride]; - unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width]; - int y; - for (y = nj.comp[0].height - 1; y; --y) { - njCopyMem(pout, pin, nj.comp[0].width); - pin += nj.comp[0].stride; - pout += nj.comp[0].width; - } - nj.comp[0].stride = nj.comp[0].width; - } -} - -void njInit(void) { - njFillMem(&nj, 0, sizeof(nj_context_t)); -} - -void njDone(void) { - int i; - for (i = 0; i < 3; ++i) - if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels); - if (nj.rgb) njFreeMem((void*) nj.rgb); - njInit(); -} - -nj_result_t njDecode(const void* jpeg, const int size) { - njDone(); - nj.pos = (const unsigned char*) jpeg; - nj.size = size & 0x7FFFFFFF; - if (nj.size < 2) return NJ_NO_JPEG; - if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG; - njSkip(2); - while (!nj.error) { - if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR; - njSkip(2); - switch (nj.pos[-1]) { - case 0xC0: njDecodeSOF(); break; - case 0xC4: njDecodeDHT(); break; - case 0xDB: njDecodeDQT(); break; - case 0xDD: njDecodeDRI(); break; - case 0xDA: njDecodeScan(); break; - case 0xFE: njSkipMarker(); break; - default: - if ((nj.pos[-1] & 0xF0) == 0xE0) - njSkipMarker(); - else - return NJ_UNSUPPORTED; - } - } - if (nj.error != __NJ_FINISHED) return nj.error; - nj.error = NJ_OK; - njConvert(); - return nj.error; -} - -int njGetWidth(void) { return nj.width; } -int njGetHeight(void) { return nj.height; } -int njIsColor(void) { return (nj.ncomp != 1); } -unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; } -int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; } - -#endif // _NJ_INCLUDE_HEADER_ONLY +// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder +// version 1.3.5 (2016-11-14) +// Copyright (c) 2009-2016 Martin J. Fiedler +// published under the terms of the MIT license +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + + +/////////////////////////////////////////////////////////////////////////////// +// DOCUMENTATION SECTION // +// read this if you want to know what this is all about // +/////////////////////////////////////////////////////////////////////////////// + +// INTRODUCTION +// ============ +// +// This is a minimal decoder for baseline JPEG images. It accepts memory dumps +// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit +// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files +// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are +// not supported. All YCbCr subsampling schemes with power-of-two ratios are +// supported, as are restart intervals. Progressive or lossless JPEG is not +// supported. +// Summed up, NanoJPEG should be able to decode all images from digital cameras +// and most common forms of other non-progressive JPEG images. +// The decoder is not optimized for speed, it's optimized for simplicity and +// small code. Image quality should be at a reasonable level. A bicubic chroma +// upsampling filter ensures that subsampled YCbCr images are rendered in +// decent quality. The decoder is not meant to deal with broken JPEG files in +// a graceful manner; if anything is wrong with the bitstream, decoding will +// simply fail. +// The code should work with every modern C compiler without problems and +// should not emit any warnings. It uses only (at least) 32-bit integer +// arithmetic and is supposed to be endianness independent and 64-bit clean. +// However, it is not thread-safe. + + +// COMPILE-TIME CONFIGURATION +// ========================== +// +// The following aspects of NanoJPEG can be controlled with preprocessor +// defines: +// +// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example +// program. +// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header +// file for NanoJPEG. Example: +// #define _NJ_INCLUDE_HEADER_ONLY +// #include "nanojpeg.c" +// int main(void) { +// njInit(); +// // your code here +// njDone(); +// } +// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy() +// functions from the standard C library (default). +// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode, +// external functions njAlloc(), njFreeMem(), +// njFillMem() and njCopyMem() need to be defined +// and implemented somewhere. +// NJ_USE_WIN32=0 = Normal mode (default). +// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and +// NJ_USE_LIBC=0, NanoJPEG will use its own +// implementations of the required C library +// functions (default if compiling with MSVC and +// NJ_USE_LIBC=0). +// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter +// (default). +// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling +// (bad quality, but faster and less code). + + +// API +// === +// +// For API documentation, read the "header section" below. + + +// EXAMPLE +// ======= +// +// A few pages below, you can find an example program that uses NanoJPEG to +// convert JPEG files into PGM or PPM. To compile it, use something like +// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c +// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :) +// The only thing you might need is -Wno-shift-negative-value, because this +// code relies on the target machine using two's complement arithmetic, but +// the C standard does not, even though *any* practically useful machine +// nowadays uses two's complement. + + +/////////////////////////////////////////////////////////////////////////////// +// HEADER SECTION // +// copy and pase this into nanojpeg.h if you want // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _NANOJPEG_H +#define _NANOJPEG_H + +// nj_result_t: Result codes for njDecode(). +typedef enum _nj_result { + NJ_OK = 0, // no error, decoding successful + NJ_NO_JPEG, // not a JPEG file + NJ_UNSUPPORTED, // unsupported format + NJ_OUT_OF_MEM, // out of memory + NJ_INTERNAL_ERR, // internal error + NJ_SYNTAX_ERROR, // syntax error + __NJ_FINISHED, // used internally, will never be reported +} nj_result_t; + +// njInit: Initialize NanoJPEG. +// For safety reasons, this should be called at least one time before using +// using any of the other NanoJPEG functions. +void njInit(void); + +// njDecode: Decode a JPEG image. +// Decodes a memory dump of a JPEG file into internal buffers. +// Parameters: +// jpeg = The pointer to the memory dump. +// size = The size of the JPEG file. +// Return value: The error code in case of failure, or NJ_OK (zero) on success. +nj_result_t njDecode(const void* jpeg, const int size); + +// njGetWidth: Return the width (in pixels) of the most recently decoded +// image. If njDecode() failed, the result of njGetWidth() is undefined. +int njGetWidth(void); + +// njGetHeight: Return the height (in pixels) of the most recently decoded +// image. If njDecode() failed, the result of njGetHeight() is undefined. +int njGetHeight(void); + +// njIsColor: Return 1 if the most recently decoded image is a color image +// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result +// of njGetWidth() is undefined. +int njIsColor(void); + +// njGetImage: Returns the decoded image data. +// Returns a pointer to the most recently image. The memory layout it byte- +// oriented, top-down, without any padding between lines. Pixels of color +// images will be stored as three consecutive bytes for the red, green and +// blue channels. This data format is thus compatible with the PGM or PPM +// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8. +// If njDecode() failed, the result of njGetImage() is undefined. +unsigned char* njGetImage(void); + +// njGetImageSize: Returns the size (in bytes) of the image data returned +// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is +// undefined. +int njGetImageSize(void); + +// njDone: Uninitialize NanoJPEG. +// Resets NanoJPEG's internal state and frees all memory that has been +// allocated at run-time by NanoJPEG. It is still possible to decode another +// image after a njDone() call. +void njDone(void); + +#endif//_NANOJPEG_H + + +/////////////////////////////////////////////////////////////////////////////// +// CONFIGURATION SECTION // +// adjust the default settings for the NJ_ defines here // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef NJ_USE_LIBC + #define NJ_USE_LIBC 1 +#endif + +#ifndef NJ_USE_WIN32 + #ifdef _MSC_VER + #define NJ_USE_WIN32 (!NJ_USE_LIBC) + #else + #define NJ_USE_WIN32 0 + #endif +#endif + +#ifndef NJ_CHROMA_FILTER + #define NJ_CHROMA_FILTER 1 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// EXAMPLE PROGRAM // +// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) // +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _NJ_EXAMPLE_PROGRAM + +#include +#include +#include + +int main(int argc, char* argv[]) { + int size; + char *buf; + FILE *f; + + if (argc < 2) { + printf("Usage: %s []\n", argv[0]); + return 2; + } + f = fopen(argv[1], "rb"); + if (!f) { + printf("Error opening the input file.\n"); + return 1; + } + fseek(f, 0, SEEK_END); + size = (int) ftell(f); + buf = (char*) malloc(size); + fseek(f, 0, SEEK_SET); + size = (int) fread(buf, 1, size, f); + fclose(f); + + njInit(); + if (njDecode(buf, size)) { + free((void*)buf); + printf("Error decoding the input file.\n"); + return 1; + } + free((void*)buf); + + f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb"); + if (!f) { + printf("Error opening the output file.\n"); + return 1; + } + fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight()); + fwrite(njGetImage(), 1, njGetImageSize(), f); + fclose(f); + njDone(); + return 0; +} + +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// IMPLEMENTATION SECTION // +// you may stop reading here // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _NJ_INCLUDE_HEADER_ONLY + +#ifdef _MSC_VER + #define NJ_INLINE static __inline + #define NJ_FORCE_INLINE static __forceinline +#else + #define NJ_INLINE static inline + #define NJ_FORCE_INLINE static inline +#endif + +#if NJ_USE_LIBC + #include + #include + #define njAllocMem malloc + #define njFreeMem free + #define njFillMem memset + #define njCopyMem memcpy +#elif NJ_USE_WIN32 + #include + #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size))) + #define njFreeMem(block) ((void) LocalFree((HLOCAL) block)) + NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm { + mov edi, block + mov al, value + mov ecx, count + rep stosb + } } + NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm { + mov edi, dest + mov esi, src + mov ecx, count + rep movsb + } } +#else + extern void* njAllocMem(int size); + extern void njFreeMem(void* block); + extern void njFillMem(void* block, unsigned char byte, int size); + extern void njCopyMem(void* dest, const void* src, int size); +#endif + +typedef struct _nj_code { + unsigned char bits, code; +} nj_vlc_code_t; + +typedef struct _nj_cmp { + int cid; + int ssx, ssy; + int width, height; + int stride; + int qtsel; + int actabsel, dctabsel; + int dcpred; + unsigned char *pixels; +} nj_component_t; + +typedef struct _nj_ctx { + nj_result_t error; + const unsigned char *pos; + int size; + int length; + int width, height; + int mbwidth, mbheight; + int mbsizex, mbsizey; + int ncomp; + nj_component_t comp[3]; + int qtused, qtavail; + unsigned char qtab[4][64]; + nj_vlc_code_t vlctab[4][65536]; + int buf, bufbits; + int block[64]; + int rstinterval; + unsigned char *rgb; +} nj_context_t; + +static nj_context_t nj; + +static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, +11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, +42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, +38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; + +NJ_FORCE_INLINE unsigned char njClip(const int x) { + return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x); +} + +#define W1 2841 +#define W2 2676 +#define W3 2408 +#define W5 1609 +#define W6 1108 +#define W7 565 + +NJ_INLINE void njRowIDCT(int* blk) { + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + if (!((x1 = blk[4] << 11) + | (x2 = blk[6]) + | (x3 = blk[2]) + | (x4 = blk[1]) + | (x5 = blk[7]) + | (x6 = blk[5]) + | (x7 = blk[3]))) + { + blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3; + return; + } + x0 = (blk[0] << 11) + 128; + x8 = W7 * (x4 + x5); + x4 = x8 + (W1 - W7) * x4; + x5 = x8 - (W1 + W7) * x5; + x8 = W3 * (x6 + x7); + x6 = x8 - (W3 - W5) * x6; + x7 = x8 - (W3 + W5) * x7; + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2); + x2 = x1 - (W2 + W6) * x2; + x3 = x1 + (W2 - W6) * x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + blk[0] = (x7 + x1) >> 8; + blk[1] = (x3 + x2) >> 8; + blk[2] = (x0 + x4) >> 8; + blk[3] = (x8 + x6) >> 8; + blk[4] = (x8 - x6) >> 8; + blk[5] = (x0 - x4) >> 8; + blk[6] = (x3 - x2) >> 8; + blk[7] = (x7 - x1) >> 8; +} + +NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) { + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + if (!((x1 = blk[8*4] << 8) + | (x2 = blk[8*6]) + | (x3 = blk[8*2]) + | (x4 = blk[8*1]) + | (x5 = blk[8*7]) + | (x6 = blk[8*5]) + | (x7 = blk[8*3]))) + { + x1 = njClip(((blk[0] + 32) >> 6) + 128); + for (x0 = 8; x0; --x0) { + *out = (unsigned char) x1; + out += stride; + } + return; + } + x0 = (blk[0] << 8) + 8192; + x8 = W7 * (x4 + x5) + 4; + x4 = (x8 + (W1 - W7) * x4) >> 3; + x5 = (x8 - (W1 + W7) * x5) >> 3; + x8 = W3 * (x6 + x7) + 4; + x6 = (x8 - (W3 - W5) * x6) >> 3; + x7 = (x8 - (W3 + W5) * x7) >> 3; + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2) + 4; + x2 = (x1 - (W2 + W6) * x2) >> 3; + x3 = (x1 + (W2 - W6) * x3) >> 3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + *out = njClip(((x7 + x1) >> 14) + 128); out += stride; + *out = njClip(((x3 + x2) >> 14) + 128); out += stride; + *out = njClip(((x0 + x4) >> 14) + 128); out += stride; + *out = njClip(((x8 + x6) >> 14) + 128); out += stride; + *out = njClip(((x8 - x6) >> 14) + 128); out += stride; + *out = njClip(((x0 - x4) >> 14) + 128); out += stride; + *out = njClip(((x3 - x2) >> 14) + 128); out += stride; + *out = njClip(((x7 - x1) >> 14) + 128); +} + +#define njThrow(e) do { nj.error = e; return; } while (0) +#define njCheckError() do { if (nj.error) return; } while (0) + +static int njShowBits(int bits) { + unsigned char newbyte; + if (!bits) return 0; + while (nj.bufbits < bits) { + if (nj.size <= 0) { + nj.buf = (nj.buf << 8) | 0xFF; + nj.bufbits += 8; + continue; + } + newbyte = *nj.pos++; + nj.size--; + nj.bufbits += 8; + nj.buf = (nj.buf << 8) | newbyte; + if (newbyte == 0xFF) { + if (nj.size) { + unsigned char marker = *nj.pos++; + nj.size--; + switch (marker) { + case 0x00: + case 0xFF: + break; + case 0xD9: nj.size = 0; break; + default: + if ((marker & 0xF8) != 0xD0) + nj.error = NJ_SYNTAX_ERROR; + else { + nj.buf = (nj.buf << 8) | marker; + nj.bufbits += 8; + } + } + } else + nj.error = NJ_SYNTAX_ERROR; + } + } + return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1); +} + +NJ_INLINE void njSkipBits(int bits) { + if (nj.bufbits < bits) + (void) njShowBits(bits); + nj.bufbits -= bits; +} + +NJ_INLINE int njGetBits(int bits) { + int res = njShowBits(bits); + njSkipBits(bits); + return res; +} + +NJ_INLINE void njByteAlign(void) { + nj.bufbits &= 0xF8; +} + +static void njSkip(int count) { + nj.pos += count; + nj.size -= count; + nj.length -= count; + if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR; +} + +NJ_INLINE unsigned short njDecode16(const unsigned char *pos) { + return (pos[0] << 8) | pos[1]; +} + +static void njDecodeLength(void) { + if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR); + nj.length = njDecode16(nj.pos); + if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR); + njSkip(2); +} + +NJ_INLINE void njSkipMarker(void) { + njDecodeLength(); + njSkip(nj.length); +} + +NJ_INLINE void njDecodeSOF(void) { + int i, ssxmax = 0, ssymax = 0; + nj_component_t* c; + njDecodeLength(); + njCheckError(); + if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR); + if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED); + nj.height = njDecode16(nj.pos+1); + nj.width = njDecode16(nj.pos+3); + if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR); + nj.ncomp = nj.pos[5]; + njSkip(6); + switch (nj.ncomp) { + case 1: + case 3: + break; + default: + njThrow(NJ_UNSUPPORTED); + } + if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR); + for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { + c->cid = nj.pos[0]; + if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR); + if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two + if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR); + if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two + if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR); + njSkip(3); + nj.qtused |= 1 << c->qtsel; + if (c->ssx > ssxmax) ssxmax = c->ssx; + if (c->ssy > ssymax) ssymax = c->ssy; + } + if (nj.ncomp == 1) { + c = nj.comp; + c->ssx = c->ssy = ssxmax = ssymax = 1; + } + nj.mbsizex = ssxmax << 3; + nj.mbsizey = ssymax << 3; + nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex; + nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey; + for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { + c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax; + c->height = (nj.height * c->ssy + ssymax - 1) / ssymax; + c->stride = nj.mbwidth * c->ssx << 3; + if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED); + if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM); + } + if (nj.ncomp == 3) { + nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp); + if (!nj.rgb) njThrow(NJ_OUT_OF_MEM); + } + njSkip(nj.length); +} + +NJ_INLINE void njDecodeDHT(void) { + int codelen, currcnt, remain, spread, i, j; + nj_vlc_code_t *vlc; + static unsigned char counts[16]; + njDecodeLength(); + njCheckError(); + while (nj.length >= 17) { + i = nj.pos[0]; + if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR); + if (i & 0x02) njThrow(NJ_UNSUPPORTED); + i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value + for (codelen = 1; codelen <= 16; ++codelen) + counts[codelen - 1] = nj.pos[codelen]; + njSkip(17); + vlc = &nj.vlctab[i][0]; + remain = spread = 65536; + for (codelen = 1; codelen <= 16; ++codelen) { + spread >>= 1; + currcnt = counts[codelen - 1]; + if (!currcnt) continue; + if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR); + remain -= currcnt << (16 - codelen); + if (remain < 0) njThrow(NJ_SYNTAX_ERROR); + for (i = 0; i < currcnt; ++i) { + register unsigned char code = nj.pos[i]; + for (j = spread; j; --j) { + vlc->bits = (unsigned char) codelen; + vlc->code = code; + ++vlc; + } + } + njSkip(currcnt); + } + while (remain--) { + vlc->bits = 0; + ++vlc; + } + } + if (nj.length) njThrow(NJ_SYNTAX_ERROR); +} + +NJ_INLINE void njDecodeDQT(void) { + int i; + unsigned char *t; + njDecodeLength(); + njCheckError(); + while (nj.length >= 65) { + i = nj.pos[0]; + if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR); + nj.qtavail |= 1 << i; + t = &nj.qtab[i][0]; + for (i = 0; i < 64; ++i) + t[i] = nj.pos[i + 1]; + njSkip(65); + } + if (nj.length) njThrow(NJ_SYNTAX_ERROR); +} + +NJ_INLINE void njDecodeDRI(void) { + njDecodeLength(); + njCheckError(); + if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR); + nj.rstinterval = njDecode16(nj.pos); + njSkip(nj.length); +} + +static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) { + int value = njShowBits(16); + int bits = vlc[value].bits; + if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; } + njSkipBits(bits); + value = vlc[value].code; + if (code) *code = (unsigned char) value; + bits = value & 15; + if (!bits) return 0; + value = njGetBits(bits); + if (value < (1 << (bits - 1))) + value += ((-1) << bits) + 1; + return value; +} + +NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) { + unsigned char code = 0; + int value, coef = 0; + njFillMem(nj.block, 0, sizeof(nj.block)); + c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL); + nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0]; + do { + value = njGetVLC(&nj.vlctab[c->actabsel][0], &code); + if (!code) break; // EOB + if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR); + coef += (code >> 4) + 1; + if (coef > 63) njThrow(NJ_SYNTAX_ERROR); + nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef]; + } while (coef < 63); + for (coef = 0; coef < 64; coef += 8) + njRowIDCT(&nj.block[coef]); + for (coef = 0; coef < 8; ++coef) + njColIDCT(&nj.block[coef], &out[coef], c->stride); +} + +NJ_INLINE void njDecodeScan(void) { + int i, mbx, mby, sbx, sby; + int rstcount = nj.rstinterval, nextrst = 0; + nj_component_t* c; + njDecodeLength(); + njCheckError(); + if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR); + if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED); + njSkip(1); + for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { + if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR); + if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR); + c->dctabsel = nj.pos[1] >> 4; + c->actabsel = (nj.pos[1] & 1) | 2; + njSkip(2); + } + if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED); + njSkip(nj.length); + for (mbx = mby = 0;;) { + for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) + for (sby = 0; sby < c->ssy; ++sby) + for (sbx = 0; sbx < c->ssx; ++sbx) { + njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]); + njCheckError(); + } + if (++mbx >= nj.mbwidth) { + mbx = 0; + if (++mby >= nj.mbheight) break; + } + if (nj.rstinterval && !(--rstcount)) { + njByteAlign(); + i = njGetBits(16); + if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR); + nextrst = (nextrst + 1) & 7; + rstcount = nj.rstinterval; + for (i = 0; i < 3; ++i) + nj.comp[i].dcpred = 0; + } + } + nj.error = __NJ_FINISHED; +} + +#if NJ_CHROMA_FILTER + +#define CF4A (-9) +#define CF4B (111) +#define CF4C (29) +#define CF4D (-3) +#define CF3A (28) +#define CF3B (109) +#define CF3C (-9) +#define CF3X (104) +#define CF3Y (27) +#define CF3Z (-3) +#define CF2A (139) +#define CF2B (-11) +#define CF(x) njClip(((x) + 64) >> 7) + +NJ_INLINE void njUpsampleH(nj_component_t* c) { + const int xmax = c->width - 3; + unsigned char *out, *lin, *lout; + int x, y; + out = (unsigned char*) njAllocMem((c->width * c->height) << 1); + if (!out) njThrow(NJ_OUT_OF_MEM); + lin = c->pixels; + lout = out; + for (y = c->height; y; --y) { + lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]); + lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]); + lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]); + for (x = 0; x < xmax; ++x) { + lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]); + lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]); + } + lin += c->stride; + lout += c->width << 1; + lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]); + lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]); + lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]); + } + c->width <<= 1; + c->stride = c->width; + njFreeMem((void*)c->pixels); + c->pixels = out; +} + +NJ_INLINE void njUpsampleV(nj_component_t* c) { + const int w = c->width, s1 = c->stride, s2 = s1 + s1; + unsigned char *out, *cin, *cout; + int x, y; + out = (unsigned char*) njAllocMem((c->width * c->height) << 1); + if (!out) njThrow(NJ_OUT_OF_MEM); + for (x = 0; x < w; ++x) { + cin = &c->pixels[x]; + cout = &out[x]; + *cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w; + *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w; + *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w; + cin += s1; + for (y = c->height - 3; y; --y) { + *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w; + *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w; + cin += s1; + } + cin += s1; + *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w; + *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w; + *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]); + } + c->height <<= 1; + c->stride = c->width; + njFreeMem((void*) c->pixels); + c->pixels = out; +} + +#else + +NJ_INLINE void njUpsample(nj_component_t* c) { + int x, y, xshift = 0, yshift = 0; + unsigned char *out, *lin, *lout; + while (c->width < nj.width) { c->width <<= 1; ++xshift; } + while (c->height < nj.height) { c->height <<= 1; ++yshift; } + out = (unsigned char*) njAllocMem(c->width * c->height); + if (!out) njThrow(NJ_OUT_OF_MEM); + lin = c->pixels; + lout = out; + for (y = 0; y < c->height; ++y) { + lin = &c->pixels[(y >> yshift) * c->stride]; + for (x = 0; x < c->width; ++x) + lout[x] = lin[x >> xshift]; + lout += c->width; + } + c->stride = c->width; + njFreeMem((void*) c->pixels); + c->pixels = out; +} + +#endif + +NJ_INLINE void njConvert(void) { + int i; + nj_component_t* c; + for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) { + #if NJ_CHROMA_FILTER + while ((c->width < nj.width) || (c->height < nj.height)) { + if (c->width < nj.width) njUpsampleH(c); + njCheckError(); + if (c->height < nj.height) njUpsampleV(c); + njCheckError(); + } + #else + if ((c->width < nj.width) || (c->height < nj.height)) + njUpsample(c); + #endif + if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR); + } + if (nj.ncomp == 3) { + // convert to RGB + int x, yy; + unsigned char *prgb = nj.rgb; + const unsigned char *py = nj.comp[0].pixels; + const unsigned char *pcb = nj.comp[1].pixels; + const unsigned char *pcr = nj.comp[2].pixels; + for (yy = nj.height; yy; --yy) { + for (x = 0; x < nj.width; ++x) { + register int y = py[x] << 8; + register int cb = pcb[x] - 128; + register int cr = pcr[x] - 128; + *prgb++ = njClip((y + 359 * cr + 128) >> 8); + *prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8); + *prgb++ = njClip((y + 454 * cb + 128) >> 8); + } + py += nj.comp[0].stride; + pcb += nj.comp[1].stride; + pcr += nj.comp[2].stride; + } + } else if (nj.comp[0].width != nj.comp[0].stride) { + // grayscale -> only remove stride + unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride]; + unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width]; + int y; + for (y = nj.comp[0].height - 1; y; --y) { + njCopyMem(pout, pin, nj.comp[0].width); + pin += nj.comp[0].stride; + pout += nj.comp[0].width; + } + nj.comp[0].stride = nj.comp[0].width; + } +} + +void njInit(void) { + njFillMem(&nj, 0, sizeof(nj_context_t)); +} + +void njDone(void) { + int i; + for (i = 0; i < 3; ++i) + if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels); + if (nj.rgb) njFreeMem((void*) nj.rgb); + njInit(); +} + +nj_result_t njDecode(const void* jpeg, const int size) { + njDone(); + nj.pos = (const unsigned char*) jpeg; + nj.size = size & 0x7FFFFFFF; + if (nj.size < 2) return NJ_NO_JPEG; + if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG; + njSkip(2); + while (!nj.error) { + if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR; + njSkip(2); + switch (nj.pos[-1]) { + case 0xC0: njDecodeSOF(); break; + case 0xC4: njDecodeDHT(); break; + case 0xDB: njDecodeDQT(); break; + case 0xDD: njDecodeDRI(); break; + case 0xDA: njDecodeScan(); break; + case 0xFE: njSkipMarker(); break; + default: + if ((nj.pos[-1] & 0xF0) == 0xE0) + njSkipMarker(); + else + return NJ_UNSUPPORTED; + } + } + if (nj.error != __NJ_FINISHED) return nj.error; + nj.error = NJ_OK; + njConvert(); + return nj.error; +} + +int njGetWidth(void) { return nj.width; } +int njGetHeight(void) { return nj.height; } +int njIsColor(void) { return (nj.ncomp != 1); } +unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; } +int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; } + +#endif // _NJ_INCLUDE_HEADER_ONLY diff --git a/libs/nlohmann/LICENSE.md b/libs/nlohmann/LICENSE.md index 8b0f7002..6ff79936 100644 --- a/libs/nlohmann/LICENSE.md +++ b/libs/nlohmann/LICENSE.md @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2013-2018 Niels Lohmann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2013-2018 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/nlohmann/json.hpp b/libs/nlohmann/json.hpp index 6b6655af..d41bff7d 100644 --- a/libs/nlohmann/json.hpp +++ b/libs/nlohmann/json.hpp @@ -1,17300 +1,17300 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.1.2 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -Copyright (c) 2013-2018 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 1 -#define NLOHMANN_JSON_VERSION_PATCH 2 - -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#include // istream, ostream -#include // iterator_traits, random_access_iterator_tag -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap - -// #include -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -template -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - -#endif - -// #include - - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) -#else - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) -#endif - -// override exception macros -#if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER -#endif -#if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER -#endif -#if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER -#endif - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - -// #include - - -#include // not -#include // size_t -#include // numeric_limits -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // declval - -// #include - -// #include - - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -// source: https://stackoverflow.com/a/37193089/4116453 - -template -struct is_complete_type : std::false_type {}; - -template -struct is_complete_type : std::true_type {}; - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -template -struct is_compatible_complete_type -{ - static constexpr bool value = - not std::is_base_of::value and - not is_basic_json::value and - not is_basic_json_nested_type::value and - has_to_json::value; -}; - -template -struct is_compatible_type - : conjunction, - is_compatible_complete_type> -{ -}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} -} - -// #include - - -#include // exception -#include // runtime_error -#include // to_string - -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// - -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | -json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; -} -} - -// #include - - -#include // array -#include // and -#include // size_t -#include // uint8_t - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} -} -} - -// #include - - -#include // transform -#include // array -#include // and, not -#include // forward_list -#include // inserter, front_inserter, end -#include // string -#include // tuple, make_tuple -#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include // pair, declval -#include // valarray - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -// overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_UNLIKELY(not j.is_boolean())) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); - } - b = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_UNLIKELY(not j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); - } - s = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr(); -} - -// forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get(); - }); -} - -// valarray doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::valarray& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - l.resize(j.size()); - std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); -} - -template -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) -{ - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval()), - void()) -{ - using std::end; - - arr.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type::value and - not std::is_same::value and - std::is_constructible < - BasicJsonType, typename CompatibleArrayType::value_type >::value, - int > = 0 > -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + - std::string(j.type_name()))); - } - - from_json_array_impl(j, arr, priority_tag<2> {}); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) -{ - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); - } - - auto inner_object = j.template get_ptr(); - using value_type = typename CompatibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(obj, obj.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get()); - }); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, std::pair& p) -{ - p = {j.at(0).template get(), j.at(1).template get()}; -} - -template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) -{ - t = std::make_tuple(j.at(Idx).template get::type>()...); -} - -template -void from_json(const BasicJsonType& j, std::tuple& t) -{ - from_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct from_json_fn -{ - private: - template - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `from_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace -{ -constexpr const auto& from_json = detail::static_const::value; -} -} - -// #include - - -#include // or, and, not -#include // begin, end -#include // tuple, get -#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type -#include // move, forward, declval, pair -#include // valarray -#include // vector - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -////////////////// -// constructors // -////////////////// - -template struct external_constructor; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_type = value_t::string; - j.m_value = std::move(s); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_type = value_t::array; - j.m_value = std::move(arr); - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_value.array->push_back(x); - } - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_type = value_t::object; - j.m_value = std::move(obj); - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor::construct(j, b); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor::construct(j, s); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor::construct(j, std::move(s)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); -} - -template -void to_json(BasicJsonType& j, const std::vector& e) -{ - external_constructor::construct(j, e); -} - -template::value or - std::is_same::value, - int> = 0> -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor::construct(j, arr); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, std::valarray arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor::construct(j, obj); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor::construct(j, std::move(obj)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) -{ - external_constructor::construct(j, arr); -} - -template -void to_json(BasicJsonType& j, const std::pair& p) -{ - j = {p.first, p.second}; -} - -template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) -{ - j = {std::get(t)...}; -} - -template -void to_json(BasicJsonType& j, const std::tuple& t) -{ - to_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct to_json_fn -{ - private: - template - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } - - template - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) - { - return call(j, std::forward(val), priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `to_json` function -namespace -{ -constexpr const auto& to_json = detail::static_const::value; -} -} - -// #include - - -#include // min -#include // array -#include // assert -#include // size_t -#include // strlen -#include // streamsize, streamoff, streampos -#include // istream -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -// #include - - -namespace nlohmann -{ -namespace detail -{ -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of exactly -one non-EOF character for future input. The int_type characters returned -consist of all valid char values as positive values (typically unsigned char), -plus an EOF value outside that range, specified by the value of the function -std::char_traits::eof(). This value is typically -1, but could be any -arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - /// restore the last non-eof() character to input - virtual void unget_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - { - // skip byte order mark - std::char_traits::int_type c; - if ((c = get_character()) == 0xEF) - { - if ((c = get_character()) == 0xBB) - { - if ((c = get_character()) == 0xBF) - { - return; // Ignore BOM - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xBB'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); - } - is.putback('\xEF'); - } - else if (c != std::char_traits::eof()) - { - is.unget(); // no byte order mark; process as usual - } - } - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - void unget_character() override - { - sb.sungetc(); // is.unget() avoided for performance - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l), start(b) - { - // skip byte order mark - if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') - { - cursor += 3; - } - } - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - void unget_character() noexcept override - { - if (JSON_LIKELY(cursor > start)) - { - --cursor; - } - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; -} -} - -// #include - - -#include // localeconv -#include // size_t -#include // strtof, strtod, strtold, strtoll, strtoull -#include // initializer_list -#include // hex, uppercase -#include // setw, setfill -#include // stringstream -#include // char_traits, string -#include // vector - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// - -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - default: // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } - - explicit lexer(detail::input_adapter_t adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer token_buffer. Then the - function returns successfully, token_buffer is *not* null-terminated (as it - may contain \0 bytes), and token_buffer.size() is the number of bytes in the - string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset token_buffer (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in token_buffer. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset token_buffer to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(token_buffer.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(token_buffer.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, token_buffer.data(), &endptr); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset token_buffer; current character is beginning of token - void reset() noexcept - { - token_buffer.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - current = ia->get_character(); - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /// unget current character (return it again on next get) - void unget() - { - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - ia->unget_character(); - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to token_buffer - void add(int c) - { - token_buffer.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - string_t&& move_string() - { - return std::move(token_buffer); - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - string_t token_buffer {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; -} -} - -// #include - - -#include // assert -#include // isfinite -#include // uint8_t -#include // function -#include // string -#include // move - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -//////////// -// parser // -//////////// - -/*! -@brief syntax analysis - -This class implements a recursive decent parser. -*/ -template -class parser -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using lexer_t = lexer; - using token_type = typename lexer_t::token_type; - - public: - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - using parser_callback_t = - std::function; - - /// a parser reading from an input adapter - explicit parser(detail::input_adapter_t adapter, - const parser_callback_t cb = nullptr, - const bool allow_exceptions_ = true) - : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) - {} - - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @param[in,out] result parsed JSON value - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse(const bool strict, BasicJsonType& result) - { - // read first token - get_token(); - - parse_internal(true, result); - result.assert_invariant(); - - // in strict mode, input must be completely read - if (strict) - { - get_token(); - expect(token_type::end_of_input); - } - - // in case of an error, return discarded value - if (errored) - { - result = value_t::discarded; - return; - } - - // set top-level value to null if it was discarded by the callback - // function - if (result.is_discarded()) - { - result = nullptr; - } - } - - /*! - @brief public accept interface - - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) - { - // read first token - get_token(); - - if (not accept_internal()) - { - return false; - } - - // strict => last token must be EOF - return not strict or (get_token() == token_type::end_of_input); - } - - private: - /*! - @brief the actual parser - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse_internal(bool keep, BasicJsonType& result) - { - // never parse after a parse error was detected - assert(not errored); - - // start with a discarded value - if (not result.is_discarded()) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - - switch (last_token) - { - case token_type::begin_object: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::object_start, result); - } - - if (not callback or keep) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - string_t key; - BasicJsonType value; - while (true) - { - // store key - if (not expect(token_type::value_string)) - { - return; - } - key = m_lexer.move_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - BasicJsonType k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - if (not expect(token_type::name_separator)) - { - return; - } - - // parse and add value - get_token(); - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and keep_tag and not value.is_discarded()) - { - result.m_value.object->emplace(std::move(key), std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - if (not expect(token_type::end_object)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::begin_array: - { - if (keep) - { - if (callback) - { - keep = callback(depth++, parse_event_t::array_start, result); - } - - if (not callback or keep) - { - // explicitly set result to array to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - // parse values - BasicJsonType value; - while (true) - { - // parse value - value.m_value.destroy(value.m_type); - value.m_type = value_t::discarded; - parse_internal(keep, value); - - if (JSON_UNLIKELY(errored)) - { - return; - } - - if (keep and not value.is_discarded()) - { - result.m_value.array->push_back(std::move(value)); - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - if (not expect(token_type::end_array)) - { - return; - } - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - break; - } - - case token_type::literal_null: - { - result.m_type = value_t::null; - break; - } - - case token_type::value_string: - { - result.m_type = value_t::string; - result.m_value = m_lexer.move_string(); - break; - } - - case token_type::literal_true: - { - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case token_type::literal_false: - { - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case token_type::value_unsigned: - { - result.m_type = value_t::number_unsigned; - result.m_value = m_lexer.get_number_unsigned(); - break; - } - - case token_type::value_integer: - { - result.m_type = value_t::number_integer; - result.m_value = m_lexer.get_number_integer(); - break; - } - - case token_type::value_float: - { - result.m_type = value_t::number_float; - result.m_value = m_lexer.get_number_float(); - - // throw in case of infinity or NAN - if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) - { - if (allow_exceptions) - { - JSON_THROW(out_of_range::create(406, "number overflow parsing '" + - m_lexer.get_token_string() + "'")); - } - expect(token_type::uninitialized); - } - break; - } - - case token_type::parse_error: - { - // using "uninitialized" to avoid "expected" message - if (not expect(token_type::uninitialized)) - { - return; - } - break; // LCOV_EXCL_LINE - } - - default: - { - // the last token was unexpected; we expected a value - if (not expect(token_type::literal_or_value)) - { - return; - } - break; // LCOV_EXCL_LINE - } - } - - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result.m_value.destroy(result.m_type); - result.m_type = value_t::discarded; - } - } - - /*! - @brief the actual acceptor - - @invariant 1. The last token is not yet processed. Therefore, the caller - of this function must make sure a token has been read. - 2. When this function returns, the last token is processed. - That is, the last read character was already considered. - - This invariant makes sure that no token needs to be "unput". - */ - bool accept_internal() - { - switch (last_token) - { - case token_type::begin_object: - { - // read next token - get_token(); - - // closing } -> we are done - if (last_token == token_type::end_object) - { - return true; - } - - // parse values - while (true) - { - // parse key - if (last_token != token_type::value_string) - { - return false; - } - - // parse separator (:) - get_token(); - if (last_token != token_type::name_separator) - { - return false; - } - - // parse value - get_token(); - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - return (last_token == token_type::end_object); - } - } - - case token_type::begin_array: - { - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == token_type::end_array) - { - return true; - } - - // parse values - while (true) - { - // parse value - if (not accept_internal()) - { - return false; - } - - // comma -> next value - get_token(); - if (last_token == token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - return (last_token == token_type::end_array); - } - } - - case token_type::value_float: - { - // reject infinity or NAN - return std::isfinite(m_lexer.get_number_float()); - } - - case token_type::literal_false: - case token_type::literal_null: - case token_type::literal_true: - case token_type::value_integer: - case token_type::value_string: - case token_type::value_unsigned: - return true; - - default: // the last token was unexpected - return false; - } - } - - /// get next token from lexer - token_type get_token() - { - return (last_token = m_lexer.scan()); - } - - /*! - @throw parse_error.101 if expected token did not occur - */ - bool expect(token_type t) - { - if (JSON_UNLIKELY(t != last_token)) - { - errored = true; - expected = t; - if (allow_exceptions) - { - throw_exception(); - } - else - { - return false; - } - } - - return true; - } - - [[noreturn]] void throw_exception() const - { - std::string error_msg = "syntax error - "; - if (last_token == token_type::parse_error) - { - error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + - m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); - } - - if (expected != token_type::uninitialized) - { - error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); - } - - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); - } - - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - token_type last_token = token_type::uninitialized; - /// the lexer - lexer_t m_lexer; - /// whether a syntax error occurred - bool errored = false; - /// possible reason for the syntax error - token_type expected = token_type::uninitialized; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; -} -} - -// #include - - -#include // ptrdiff_t -#include // numeric_limits - -namespace nlohmann -{ -namespace detail -{ -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - private: - using difference_type = std::ptrdiff_t; - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); - - public: - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type n) noexcept - { - auto result = *this; - result += n; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - primitive_iterator_t& operator++() noexcept - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) noexcept - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() noexcept - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) noexcept - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) noexcept - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) noexcept - { - m_it -= n; - return *this; - } -}; -} -} - -// #include - - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; -} -} - -// #include - - -#include // not -#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next -#include // conditional, is_const, remove_const - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -// forward declare, to be able to friend it later on -template class iteration_proxy; - -/*! -@brief a template for a bidirectional iterator for the @ref basic_json class - -This class implements a both iterators (iterator and const_iterator) for the -@ref basic_json class. - -@note An iterator is called *initialized* when a pointer to a JSON value has - been set (e.g., by a constructor or a copy assignment). If the iterator is - default-constructed, it is *uninitialized* and most methods are undefined. - **The library uses assertions to detect calls on uninitialized iterators.** - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). - -@since version 1.0.0, simplified in version 2.0.9, change to bidirectional - iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) -*/ -template -class iter_impl -{ - /// allow basic_json to access private members - friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; - friend BasicJsonType; - friend iteration_proxy; - - using object_t = typename BasicJsonType::object_t; - using array_t = typename BasicJsonType::array_t; - // make sure BasicJsonType is basic_json or const basic_json - static_assert(is_basic_json::type>::value, - "iter_impl only accepts (const) basic_json"); - - public: - - /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. - /// The C++ Standard has never required user-defined iterators to derive from std::iterator. - /// A user-defined iterator should provide publicly accessible typedefs named - /// iterator_category, value_type, difference_type, pointer, and reference. - /// Note that value_type is required to be non-const, even for constant iterators. - using iterator_category = std::bidirectional_iterator_tag; - - /// the type of the values when the iterator is dereferenced - using value_type = typename BasicJsonType::value_type; - /// a type to represent differences between iterators - using difference_type = typename BasicJsonType::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename BasicJsonType::const_pointer, - typename BasicJsonType::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = - typename std::conditional::value, - typename BasicJsonType::const_reference, - typename BasicJsonType::reference>::type; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /*! - @note The conventional copy constructor and copy assignment are implicitly - defined. Combined with the following converting constructor and - assignment, they support: (1) copy from iterator to iterator, (2) - copy from const iterator to const iterator, and (3) conversion from - iterator to const iterator. However conversion from const iterator - to iterator is not defined. - */ - - /*! - @brief converting constructor - @param[in] other non-const iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl::type>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) {} - - /*! - @brief converting assignment - @param[in,out] other non-const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl::type>& other) noexcept - { - m_object = other.m_object; - m_it = other.m_it; - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - return (m_it.object_iterator == other.m_it.object_iterator); - - case value_t::array: - return (m_it.array_iterator == other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief addition of distance and iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - friend iter_impl operator+(difference_type i, const iter_impl& it) - { - auto result = it; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); - - case value_t::array: - return *std::next(m_it.array_iterator, n); - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - - default: - { - if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (JSON_LIKELY(m_object->is_object())) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator::type> m_it; -}; -} -} - -// #include - - -#include // size_t -#include // string, to_string - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/// proxy class for the items() function -template class iteration_proxy -{ - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_internal& o) const noexcept - { - return anchor != o.anchor; - } - - /// return key of the iterator - std::string key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - return std::to_string(array_index); - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - default: - return ""; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) noexcept - : container(cont) {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } -}; -} -} - -// #include - - -#include // ptrdiff_t -#include // reverse_iterator -#include // declval - -namespace nlohmann -{ -namespace detail -{ -////////////////////// -// reverse_iterator // -////////////////////// - -/*! -@brief a template for a reverse iterator class - -@tparam Base the base iterator type to reverse. Valid types are @ref -iterator (to create @ref reverse_iterator) and @ref const_iterator (to -create @ref const_reverse_iterator). - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - -@since version 1.0.0 -*/ -template -class json_reverse_iterator : public std::reverse_iterator -{ - public: - using difference_type = std::ptrdiff_t; - /// shortcut to the reverse iterator adapter - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} - - /// post-increment (it++) - json_reverse_iterator const operator++(int) - { - return static_cast(base_iterator::operator++(1)); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - return static_cast(base_iterator::operator++()); - } - - /// post-decrement (it--) - json_reverse_iterator const operator--(int) - { - return static_cast(base_iterator::operator--(1)); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - return static_cast(base_iterator::operator--()); - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - return static_cast(base_iterator::operator+=(i)); - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - return static_cast(base_iterator::operator+(i)); - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - return static_cast(base_iterator::operator-(i)); - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return base_iterator(*this) - base_iterator(other); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - auto key() const -> decltype(std::declval().key()) - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } -}; -} -} - -// #include - - -#include // copy -#include // size_t -#include // streamsize -#include // back_inserter -#include // shared_ptr, make_shared -#include // basic_ostream -#include // basic_string -#include // vector - -namespace nlohmann -{ -namespace detail -{ -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) : v(vec) {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} - - void write_character(CharType c) override - { - stream.put(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; - -/// output adapter for basic_string -template> -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(StringType& s) : str(s) {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - StringType& str; -}; - -template> -class output_adapter -{ - public: - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} - - output_adapter(StringType& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; -} -} - -// #include - - -#include // generate_n -#include // array -#include // assert -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // setw, setfill -#include // hex -#include // back_inserter -#include // numeric_limits -#include // stringstream -#include // char_traits, string -#include // make_pair, move - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR and MessagePack values -*/ -template -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using string_t = typename BasicJsonType::string_t; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_cbor(const bool strict) - { - const auto res = parse_cbor_internal(); - if (strict) - { - get(); - expect_eof(); - } - return res; - } - - /*! - @brief create a JSON value from MessagePack input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_msgpack(const bool strict) - { - const auto res = parse_msgpack_internal(); - if (strict) - { - get(); - expect_eof(); - } - return res; - } - - /*! - @brief create a JSON value from UBJSON input - - @param[in] strict whether to expect the input to be consumed completed - @return JSON value created from UBJSON input - - @throw parse_error.110 if input ended unexpectedly or the end of file was - not reached when @a strict was set to true - @throw parse_error.112 if unsupported byte was read - */ - BasicJsonType parse_ubjson(const bool strict) - { - const auto res = parse_ubjson_internal(); - if (strict) - { - get_ignore_noop(); - expect_eof(); - } - return res; - } - - /*! - @brief determine system byte order - - @return true if and only if system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static constexpr bool little_endianess(int num = 1) noexcept - { - return (*reinterpret_cast(&num) == 1); - } - - private: - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_cbor_internal(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return static_cast(current); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - return get_number(); - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - return get_number(); - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - return get_number(); - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - return get_number(); - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return static_cast(0x20 - 1 - current); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - return get_cbor_array(current & 0x1F); - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - return get_cbor_array(get_number()); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - return get_cbor_array(get_number()); - } - - case 0x9F: // array (indefinite length) - { - BasicJsonType result = value_t::array; - while (get() != 0xFF) - { - result.push_back(parse_cbor_internal(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - { - return get_cbor_object(current & 0x1F); - } - - case 0xB8: // map (one-byte uint8_t for n follows) - { - return get_cbor_object(get_number()); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - return get_cbor_object(get_number()); - } - - case 0xBF: // map (indefinite length) - { - BasicJsonType result = value_t::object; - while (get() != 0xFF) - { - auto key = get_cbor_string(); - result[key] = parse_cbor_internal(); - } - return result; - } - - case 0xF4: // false - { - return false; - } - - case 0xF5: // true - { - return true; - } - - case 0xF6: // null - { - return value_t::null; - } - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - unexpect_eof(); - const int byte2 = get(); - unexpect_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = (mant == 0) ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - BasicJsonType parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return static_cast(current); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - { - return get_msgpack_object(current & 0x0F); - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - { - return get_msgpack_array(current & 0x0F); - } - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - return get_msgpack_string(); - - case 0xC0: // nil - return value_t::null; - - case 0xC2: // false - return false; - - case 0xC3: // true - return true; - - case 0xCA: // float 32 - return get_number(); - - case 0xCB: // float 64 - return get_number(); - - case 0xCC: // uint 8 - return get_number(); - - case 0xCD: // uint 16 - return get_number(); - - case 0xCE: // uint 32 - return get_number(); - - case 0xCF: // uint 64 - return get_number(); - - case 0xD0: // int 8 - return get_number(); - - case 0xD1: // int 16 - return get_number(); - - case 0xD2: // int 32 - return get_number(); - - case 0xD3: // int 64 - return get_number(); - - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - return get_msgpack_string(); - - case 0xDC: // array 16 - { - return get_msgpack_array(get_number()); - } - - case 0xDD: // array 32 - { - return get_msgpack_array(get_number()); - } - - case 0xDE: // map 16 - { - return get_msgpack_object(get_number()); - } - - case 0xDF: // map 32 - { - return get_msgpack_object(get_number()); - } - - // positive fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return static_cast(current); - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - */ - BasicJsonType parse_ubjson_internal(const bool get_char = true) - { - return get_ubjson_value(get_char ? get_ignore_noop() : current); - } - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() - { - ++chars_read; - return (current = ia->get_character()); - } - - /*! - @return character read from the input after ignoring all 'N' entries - */ - int get_ignore_noop() - { - do - { - get(); - } - while (current == 'N'); - - return current; - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - - @return number of type @a NumberType - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes - */ - template NumberType get_number() - { - // step 1: read input into array with system's byte order - std::array vec; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - unexpect_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - NumberType result; - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return result; - } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref unexpect_eof() detects the end of - the input before we run out of string memory. - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - template - string_t get_string(const NumberType len) - { - string_t result; - std::generate_n(std::back_inserter(result), len, [this]() - { - get(); - unexpect_eof(); - return static_cast(current); - }); - return result; - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - string_t get_cbor_string() - { - unexpect_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(current & 0x1F); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - return get_string(get_number()); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - return get_string(get_number()); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - return get_string(get_number()); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - return get_string(get_number()); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - string_t result; - while (get() != 0xFF) - { - result.append(get_cbor_string()); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_cbor_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_cbor_internal(); - }); - return result; - } - - template - BasicJsonType get_cbor_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_cbor_string(); - auto val = parse_cbor_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - string_t get_msgpack_string() - { - unexpect_eof(); - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(current & 0x1F); - } - - case 0xD9: // str 8 - { - return get_string(get_number()); - } - - case 0xDA: // str 16 - { - return get_string(get_number()); - } - - case 0xDB: // str 32 - { - return get_string(get_number()); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } - - template - BasicJsonType get_msgpack_array(const NumberType len) - { - BasicJsonType result = value_t::array; - std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() - { - return parse_msgpack_internal(); - }); - return result; - } - - template - BasicJsonType get_msgpack_object(const NumberType len) - { - BasicJsonType result = value_t::object; - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - len, [this]() - { - get(); - auto key = get_msgpack_string(); - auto val = parse_msgpack_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - return result; - } - - /*! - @brief reads a UBJSON string - - This function is either called after reading the 'S' byte explicitly - indicating a string, or in case of an object key where the 'S' byte can be - left out. - - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpected byte is read - */ - string_t get_ubjson_string(const bool get_char = true) - { - if (get_char) - { - get(); // TODO: may we ignore N here? - } - - unexpect_eof(); - - switch (current) - { - case 'U': - return get_string(get_number()); - case 'i': - return get_string(get_number()); - case 'I': - return get_string(get_number()); - case 'l': - return get_string(get_number()); - case 'L': - return get_string(get_number()); - default: - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "expected a UBJSON string; last byte: 0x" + ss.str())); - } - } - - /*! - @brief determine the type and size for a container - - In the optimized UBJSON format, a type and a size can be provided to allow - for a more compact representation. - - @return pair of the size and the type - */ - std::pair get_ubjson_size_type() - { - std::size_t sz = string_t::npos; - int tc = 0; - - get_ignore_noop(); - - if (current == '$') - { - tc = get(); // must not ignore 'N', because 'N' maybe the type - unexpect_eof(); - - get_ignore_noop(); - if (current != '#') - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "expected '#' after UBJSON type information; last byte: 0x" + ss.str())); - } - sz = parse_ubjson_internal(); - } - else if (current == '#') - { - sz = parse_ubjson_internal(); - } - - return std::make_pair(sz, tc); - } - - BasicJsonType get_ubjson_value(const int prefix) - { - switch (prefix) - { - case std::char_traits::eof(): // EOF - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - - case 'T': // true - return true; - case 'F': // false - return false; - - case 'Z': // null - return nullptr; - - case 'U': - return get_number(); - case 'i': - return get_number(); - case 'I': - return get_number(); - case 'l': - return get_number(); - case 'L': - return get_number(); - case 'd': - return get_number(); - case 'D': - return get_number(); - - case 'C': // char - { - get(); - unexpect_eof(); - if (JSON_UNLIKELY(current > 127)) - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, - "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str())); - } - return string_t(1, static_cast(current)); - } - - case 'S': // string - return get_ubjson_string(); - - case '[': // array - return get_ubjson_array(); - - case '{': // object - return get_ubjson_object(); - - default: // anything else - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, - "error reading UBJSON; last byte: 0x" + ss.str())); - } - } - - BasicJsonType get_ubjson_array() - { - BasicJsonType result = value_t::array; - const auto size_and_type = get_ubjson_size_type(); - - if (size_and_type.first != string_t::npos) - { - if (JSON_UNLIKELY(size_and_type.first > result.max_size())) - { - JSON_THROW(out_of_range::create(408, - "excessive array size: " + std::to_string(size_and_type.first))); - } - - if (size_and_type.second != 0) - { - if (size_and_type.second != 'N') - { - std::generate_n(std::back_inserter(*result.m_value.array), - size_and_type.first, [this, size_and_type]() - { - return get_ubjson_value(size_and_type.second); - }); - } - } - else - { - std::generate_n(std::back_inserter(*result.m_value.array), - size_and_type.first, [this]() - { - return parse_ubjson_internal(); - }); - } - } - else - { - while (current != ']') - { - result.push_back(parse_ubjson_internal(false)); - get_ignore_noop(); - } - } - - return result; - } - - BasicJsonType get_ubjson_object() - { - BasicJsonType result = value_t::object; - const auto size_and_type = get_ubjson_size_type(); - - if (size_and_type.first != string_t::npos) - { - if (JSON_UNLIKELY(size_and_type.first > result.max_size())) - { - JSON_THROW(out_of_range::create(408, - "excessive object size: " + std::to_string(size_and_type.first))); - } - - if (size_and_type.second != 0) - { - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - size_and_type.first, [this, size_and_type]() - { - auto key = get_ubjson_string(); - auto val = get_ubjson_value(size_and_type.second); - return std::make_pair(std::move(key), std::move(val)); - }); - } - else - { - std::generate_n(std::inserter(*result.m_value.object, - result.m_value.object->end()), - size_and_type.first, [this]() - { - auto key = get_ubjson_string(); - auto val = parse_ubjson_internal(); - return std::make_pair(std::move(key), std::move(val)); - }); - } - } - else - { - while (current != '}') - { - auto key = get_ubjson_string(false); - result[std::move(key)] = parse_ubjson_internal(); - get_ignore_noop(); - } - } - - return result; - } - - /*! - @brief throw if end of input is not reached - @throw parse_error.110 if input not ended - */ - void expect_eof() const - { - if (JSON_UNLIKELY(current != std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); - } - } - - /*! - @briefthrow if end of input is reached - @throw parse_error.110 if input ended - */ - void unexpect_eof() const - { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = little_endianess(); -}; -} -} - -// #include - - -#include // reverse -#include // array -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // numeric_limits - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary writer // -/////////////////// - -/*! -@brief serialization to CBOR and MessagePack values -*/ -template -class binary_writer -{ - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t adapter) : oa(adapter) - { - assert(oa); - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_cbor(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(static_cast(0xF6)); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_value.boolean - ? static_cast(0xF5) - : static_cast(0xF4)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_integer)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - write_number(static_cast(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x38)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x39)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x3A)); - write_number(static_cast(positive_number)); - } - else - { - oa->write_character(static_cast(0x3B)); - write_number(static_cast(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x18)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x19)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x1A)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - oa->write_character(static_cast(0x1B)); - write_number(static_cast(j.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: // Double-Precision Float - { - oa->write_character(static_cast(0xFB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast(0x60 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x78)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x79)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x7A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x7B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast(0x80 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x98)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x99)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x9A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0x9B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast(0xA0 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0xB8)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0xB9)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0xBA)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(static_cast(0xBB)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - default: - break; - } - } - - /*! - @brief[in] j JSON value to serialize - */ - void write_msgpack(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: // nil - { - oa->write_character(static_cast(0xC0)); - break; - } - - case value_t::boolean: // true and false - { - oa->write_character(j.m_value.boolean - ? static_cast(0xC3) - : static_cast(0xC2)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 8 - oa->write_character(static_cast(0xD0)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 16 - oa->write_character(static_cast(0xD1)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 32 - oa->write_character(static_cast(0xD2)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 64 - oa->write_character(static_cast(0xD3)); - write_number(static_cast(j.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(static_cast(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(static_cast(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(static_cast(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(static_cast(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - break; - } - - case value_t::number_float: // float 64 - { - oa->write_character(static_cast(0xCB)); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast(0xA0 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 8 - oa->write_character(static_cast(0xD9)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 16 - oa->write_character(static_cast(0xDA)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 32 - oa->write_character(static_cast(0xDB)); - write_number(static_cast(N)); - } - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 16 - oa->write_character(static_cast(0xDC)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 32 - oa->write_character(static_cast(0xDD)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 16 - oa->write_character(static_cast(0xDE)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 32 - oa->write_character(static_cast(0xDF)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - default: - break; - } - } - - /*! - @param[in] j JSON value to serialize - @param[in] use_count whether to use '#' prefixes (optimized format) - @param[in] use_type whether to use '$' prefixes (optimized format) - @param[in] add_prefix whether prefixes need to be used for this value - */ - void write_ubjson(const BasicJsonType& j, const bool use_count, - const bool use_type, const bool add_prefix = true) - { - switch (j.type()) - { - case value_t::null: - { - if (add_prefix) - { - oa->write_character(static_cast('Z')); - } - break; - } - - case value_t::boolean: - { - if (add_prefix) - oa->write_character(j.m_value.boolean - ? static_cast('T') - : static_cast('F')); - break; - } - - case value_t::number_integer: - { - write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); - break; - } - - case value_t::number_unsigned: - { - write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); - break; - } - - case value_t::number_float: - { - write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); - break; - } - - case value_t::string: - { - if (add_prefix) - { - oa->write_character(static_cast('S')); - } - write_number_with_ubjson_prefix(j.m_value.string->size(), true); - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - if (add_prefix) - { - oa->write_character(static_cast('[')); - } - - bool prefix_required = true; - if (use_type and not j.m_value.array->empty()) - { - assert(use_count); - const char first_prefix = ubjson_prefix(j.front()); - const bool same_prefix = std::all_of(j.begin() + 1, j.end(), - [this, first_prefix](const BasicJsonType & v) - { - return ubjson_prefix(v) == first_prefix; - }); - - if (same_prefix) - { - prefix_required = false; - oa->write_character(static_cast('$')); - oa->write_character(static_cast(first_prefix)); - } - } - - if (use_count) - { - oa->write_character(static_cast('#')); - write_number_with_ubjson_prefix(j.m_value.array->size(), true); - } - - for (const auto& el : *j.m_value.array) - { - write_ubjson(el, use_count, use_type, prefix_required); - } - - if (not use_count) - { - oa->write_character(static_cast(']')); - } - - break; - } - - case value_t::object: - { - if (add_prefix) - { - oa->write_character(static_cast('{')); - } - - bool prefix_required = true; - if (use_type and not j.m_value.object->empty()) - { - assert(use_count); - const char first_prefix = ubjson_prefix(j.front()); - const bool same_prefix = std::all_of(j.begin(), j.end(), - [this, first_prefix](const BasicJsonType & v) - { - return ubjson_prefix(v) == first_prefix; - }); - - if (same_prefix) - { - prefix_required = false; - oa->write_character(static_cast('$')); - oa->write_character(static_cast(first_prefix)); - } - } - - if (use_count) - { - oa->write_character(static_cast('#')); - write_number_with_ubjson_prefix(j.m_value.object->size(), true); - } - - for (const auto& el : *j.m_value.object) - { - write_number_with_ubjson_prefix(el.first.size(), true); - oa->write_characters( - reinterpret_cast(el.first.c_str()), - el.first.size()); - write_ubjson(el.second, use_count, use_type, prefix_required); - } - - if (not use_count) - { - oa->write_character(static_cast('}')); - } - - break; - } - - default: - break; - } - } - - private: - /* - @brief write a number to output input - - @param[in] n number of type @a NumberType - @tparam NumberType the type of the number - - @note This function needs to respect the system's endianess, because bytes - in CBOR, MessagePack, and UBJSON are stored in network order (big - endian) and therefore need reordering on little endian systems. - */ - template - void write_number(const NumberType n) - { - // step 1: write number to array of length NumberType - std::array vec; - std::memcpy(vec.data(), &n, sizeof(NumberType)); - - // step 2: write array to output (with possible reordering) - if (is_little_endian) - { - // reverse byte order prior to conversion if necessary - std::reverse(vec.begin(), vec.end()); - } - - oa->write_characters(vec.data(), sizeof(NumberType)); - } - - // UBJSON: write number (floating point) - template::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if (add_prefix) - { - oa->write_character(static_cast('D')); // float64 - } - write_number(n); - } - - // UBJSON: write number (unsigned integer) - template::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); - } - else if (n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); - } - } - - // UBJSON: write number (signed integer) - template::value and - not std::is_floating_point::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); - } - else if (static_cast((std::numeric_limits::min)()) <= n and n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - // LCOV_EXCL_START - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); - } - // LCOV_EXCL_STOP - } - - /*! - @brief determine the type prefix of container values - - @note This function does not need to be 100% accurate when it comes to - integer limits. In case a number exceeds the limits of int64_t, - this will be detected by a later call to function - write_number_with_ubjson_prefix. Therefore, we return 'L' for any - value that does not fit the previous limits. - */ - char ubjson_prefix(const BasicJsonType& j) const noexcept - { - switch (j.type()) - { - case value_t::null: - return 'Z'; - - case value_t::boolean: - return j.m_value.boolean ? 'T' : 'F'; - - case value_t::number_integer: - { - if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'i'; - } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'U'; - } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'I'; - } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'l'; - } - else // no check and assume int64_t (see note above) - { - return 'L'; - } - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - return 'i'; - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - return 'U'; - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - return 'I'; - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - return 'l'; - } - else // no check and assume int64_t (see note above) - { - return 'L'; - } - } - - case value_t::number_float: - return 'D'; - - case value_t::string: - return 'S'; - - case value_t::array: - return '['; - - case value_t::object: - return '{'; - - default: // discarded values - return 'N'; - } - } - - private: - /// whether we can assume little endianess - const bool is_little_endian = binary_reader::little_endianess(); - - /// the output - output_adapter_t oa = nullptr; -}; -} -} - -// #include - - -#include // reverse, remove, fill, find, none_of -#include // array -#include // assert -#include // and, or -#include // localeconv, lconv -#include // labs, isfinite, isnan, signbit -#include // size_t, ptrdiff_t -#include // uint8_t -#include // snprintf -#include // setfill -#include // next -#include // numeric_limits -#include // string -#include // stringstream -#include // is_same - -// #include - -// #include - - -#include // assert -#include // or, and, not -#include // signbit, isfinite -#include // intN_t, uintN_t -#include // memcpy, memmove - -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief implements the Grisu2 algorithm for binary to decimal floating-point -conversion. - -This implementation is a slightly modified version of the reference -implementation which may be obtained from -http://florian.loitsch.com/publications (bench.tar.gz). - -The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. - -For a detailed description of the algorithm see: - -[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with - Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming - Language Design and Implementation, PLDI 2010 -[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", - Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language - Design and Implementation, PLDI 1996 -*/ -namespace dtoa_impl -{ - -template -Target reinterpret_bits(const Source source) -{ - static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); - - Target target; - std::memcpy(&target, &source, sizeof(Source)); - return target; -} - -struct diyfp // f * 2^e -{ - static constexpr int kPrecision = 64; // = q - - uint64_t f; - int e; - - constexpr diyfp() noexcept : f(0), e(0) {} - constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} - - /*! - @brief returns x - y - @pre x.e == y.e and x.f >= y.f - */ - static diyfp sub(const diyfp& x, const diyfp& y) noexcept - { - assert(x.e == y.e); - assert(x.f >= y.f); - - return diyfp(x.f - y.f, x.e); - } - - /*! - @brief returns x * y - @note The result is rounded. (Only the upper q bits are returned.) - */ - static diyfp mul(const diyfp& x, const diyfp& y) noexcept - { - static_assert(kPrecision == 64, "internal error"); - - // Computes: - // f = round((x.f * y.f) / 2^q) - // e = x.e + y.e + q - - // Emulate the 64-bit * 64-bit multiplication: - // - // p = u * v - // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) - // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) - // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) - // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) - // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) - // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) - // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) - // - // (Since Q might be larger than 2^32 - 1) - // - // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) - // - // (Q_hi + H does not overflow a 64-bit int) - // - // = p_lo + 2^64 p_hi - - const uint64_t u_lo = x.f & 0xFFFFFFFF; - const uint64_t u_hi = x.f >> 32; - const uint64_t v_lo = y.f & 0xFFFFFFFF; - const uint64_t v_hi = y.f >> 32; - - const uint64_t p0 = u_lo * v_lo; - const uint64_t p1 = u_lo * v_hi; - const uint64_t p2 = u_hi * v_lo; - const uint64_t p3 = u_hi * v_hi; - - const uint64_t p0_hi = p0 >> 32; - const uint64_t p1_lo = p1 & 0xFFFFFFFF; - const uint64_t p1_hi = p1 >> 32; - const uint64_t p2_lo = p2 & 0xFFFFFFFF; - const uint64_t p2_hi = p2 >> 32; - - uint64_t Q = p0_hi + p1_lo + p2_lo; - - // The full product might now be computed as - // - // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) - // p_lo = p0_lo + (Q << 32) - // - // But in this particular case here, the full p_lo is not required. - // Effectively we only need to add the highest bit in p_lo to p_hi (and - // Q_hi + 1 does not overflow). - - Q += uint64_t{1} << (64 - 32 - 1); // round, ties up - - const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); - - return diyfp(h, x.e + y.e + 64); - } - - /*! - @brief normalize x such that the significand is >= 2^(q-1) - @pre x.f != 0 - */ - static diyfp normalize(diyfp x) noexcept - { - assert(x.f != 0); - - while ((x.f >> 63) == 0) - { - x.f <<= 1; - x.e--; - } - - return x; - } - - /*! - @brief normalize x such that the result has the exponent E - @pre e >= x.e and the upper e - x.e bits of x.f must be zero. - */ - static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept - { - const int delta = x.e - target_exponent; - - assert(delta >= 0); - assert(((x.f << delta) >> delta) == x.f); - - return diyfp(x.f << delta, target_exponent); - } -}; - -struct boundaries -{ - diyfp w; - diyfp minus; - diyfp plus; -}; - -/*! -Compute the (normalized) diyfp representing the input number 'value' and its -boundaries. - -@pre value must be finite and positive -*/ -template -boundaries compute_boundaries(FloatType value) -{ - assert(std::isfinite(value)); - assert(value > 0); - - // Convert the IEEE representation into a diyfp. - // - // If v is denormal: - // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) - // If v is normalized: - // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) - - static_assert(std::numeric_limits::is_iec559, - "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); - - constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) - constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); - constexpr int kMinExp = 1 - kBias; - constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) - - using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; - - const uint64_t bits = reinterpret_bits(value); - const uint64_t E = bits >> (kPrecision - 1); - const uint64_t F = bits & (kHiddenBit - 1); - - const bool is_denormal = (E == 0); - const diyfp v = is_denormal - ? diyfp(F, kMinExp) - : diyfp(F + kHiddenBit, static_cast(E) - kBias); - - // Compute the boundaries m- and m+ of the floating-point value - // v = f * 2^e. - // - // Determine v- and v+, the floating-point predecessor and successor if v, - // respectively. - // - // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) - // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) - // - // v+ = v + 2^e - // - // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ - // between m- and m+ round to v, regardless of how the input rounding - // algorithm breaks ties. - // - // ---+-------------+-------------+-------------+-------------+--- (A) - // v- m- v m+ v+ - // - // -----------------+------+------+-------------+-------------+--- (B) - // v- m- v m+ v+ - - const bool lower_boundary_is_closer = (F == 0 and E > 1); - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); - const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) - - // Determine the normalized w+ = m+. - const diyfp w_plus = diyfp::normalize(m_plus); - - // Determine w- = m- such that e_(w-) = e_(w+). - const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); - - return {diyfp::normalize(v), w_minus, w_plus}; -} - -// Given normalized diyfp w, Grisu needs to find a (normalized) cached -// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies -// within a certain range [alpha, gamma] (Definition 3.2 from [1]) -// -// alpha <= e = e_c + e_w + q <= gamma -// -// or -// -// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q -// <= f_c * f_w * 2^gamma -// -// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies -// -// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma -// -// or -// -// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) -// -// The choice of (alpha,gamma) determines the size of the table and the form of -// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well -// in practice: -// -// The idea is to cut the number c * w = f * 2^e into two parts, which can be -// processed independently: An integral part p1, and a fractional part p2: -// -// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e -// = (f div 2^-e) + (f mod 2^-e) * 2^e -// = p1 + p2 * 2^e -// -// The conversion of p1 into decimal form requires a series of divisions and -// modulos by (a power of) 10. These operations are faster for 32-bit than for -// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be -// achieved by choosing -// -// -e >= 32 or e <= -32 := gamma -// -// In order to convert the fractional part -// -// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... -// -// into decimal form, the fraction is repeatedly multiplied by 10 and the digits -// d[-i] are extracted in order: -// -// (10 * p2) div 2^-e = d[-1] -// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... -// -// The multiplication by 10 must not overflow. It is sufficient to choose -// -// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. -// -// Since p2 = f mod 2^-e < 2^-e, -// -// -e <= 60 or e >= -60 := alpha - -constexpr int kAlpha = -60; -constexpr int kGamma = -32; - -struct cached_power // c = f * 2^e ~= 10^k -{ - uint64_t f; - int e; - int k; -}; - -/*! -For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached -power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c -satisfies (Definition 3.2 from [1]) - - alpha <= e_c + e + q <= gamma. -*/ -inline cached_power get_cached_power_for_binary_exponent(int e) -{ - // Now - // - // alpha <= e_c + e + q <= gamma (1) - // ==> f_c * 2^alpha <= c * 2^e * 2^q - // - // and since the c's are normalized, 2^(q-1) <= f_c, - // - // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) - // ==> 2^(alpha - e - 1) <= c - // - // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as - // - // k = ceil( log_10( 2^(alpha - e - 1) ) ) - // = ceil( (alpha - e - 1) * log_10(2) ) - // - // From the paper: - // "In theory the result of the procedure could be wrong since c is rounded, - // and the computation itself is approximated [...]. In practice, however, - // this simple function is sufficient." - // - // For IEEE double precision floating-point numbers converted into - // normalized diyfp's w = f * 2^e, with q = 64, - // - // e >= -1022 (min IEEE exponent) - // -52 (p - 1) - // -52 (p - 1, possibly normalize denormal IEEE numbers) - // -11 (normalize the diyfp) - // = -1137 - // - // and - // - // e <= +1023 (max IEEE exponent) - // -52 (p - 1) - // -11 (normalize the diyfp) - // = 960 - // - // This binary exponent range [-1137,960] results in a decimal exponent - // range [-307,324]. One does not need to store a cached power for each - // k in this range. For each such k it suffices to find a cached power - // such that the exponent of the product lies in [alpha,gamma]. - // This implies that the difference of the decimal exponents of adjacent - // table entries must be less than or equal to - // - // floor( (gamma - alpha) * log_10(2) ) = 8. - // - // (A smaller distance gamma-alpha would require a larger table.) - - // NB: - // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. - - constexpr int kCachedPowersSize = 79; - constexpr int kCachedPowersMinDecExp = -300; - constexpr int kCachedPowersDecStep = 8; - - static constexpr cached_power kCachedPowers[] = - { - { 0xAB70FE17C79AC6CA, -1060, -300 }, - { 0xFF77B1FCBEBCDC4F, -1034, -292 }, - { 0xBE5691EF416BD60C, -1007, -284 }, - { 0x8DD01FAD907FFC3C, -980, -276 }, - { 0xD3515C2831559A83, -954, -268 }, - { 0x9D71AC8FADA6C9B5, -927, -260 }, - { 0xEA9C227723EE8BCB, -901, -252 }, - { 0xAECC49914078536D, -874, -244 }, - { 0x823C12795DB6CE57, -847, -236 }, - { 0xC21094364DFB5637, -821, -228 }, - { 0x9096EA6F3848984F, -794, -220 }, - { 0xD77485CB25823AC7, -768, -212 }, - { 0xA086CFCD97BF97F4, -741, -204 }, - { 0xEF340A98172AACE5, -715, -196 }, - { 0xB23867FB2A35B28E, -688, -188 }, - { 0x84C8D4DFD2C63F3B, -661, -180 }, - { 0xC5DD44271AD3CDBA, -635, -172 }, - { 0x936B9FCEBB25C996, -608, -164 }, - { 0xDBAC6C247D62A584, -582, -156 }, - { 0xA3AB66580D5FDAF6, -555, -148 }, - { 0xF3E2F893DEC3F126, -529, -140 }, - { 0xB5B5ADA8AAFF80B8, -502, -132 }, - { 0x87625F056C7C4A8B, -475, -124 }, - { 0xC9BCFF6034C13053, -449, -116 }, - { 0x964E858C91BA2655, -422, -108 }, - { 0xDFF9772470297EBD, -396, -100 }, - { 0xA6DFBD9FB8E5B88F, -369, -92 }, - { 0xF8A95FCF88747D94, -343, -84 }, - { 0xB94470938FA89BCF, -316, -76 }, - { 0x8A08F0F8BF0F156B, -289, -68 }, - { 0xCDB02555653131B6, -263, -60 }, - { 0x993FE2C6D07B7FAC, -236, -52 }, - { 0xE45C10C42A2B3B06, -210, -44 }, - { 0xAA242499697392D3, -183, -36 }, - { 0xFD87B5F28300CA0E, -157, -28 }, - { 0xBCE5086492111AEB, -130, -20 }, - { 0x8CBCCC096F5088CC, -103, -12 }, - { 0xD1B71758E219652C, -77, -4 }, - { 0x9C40000000000000, -50, 4 }, - { 0xE8D4A51000000000, -24, 12 }, - { 0xAD78EBC5AC620000, 3, 20 }, - { 0x813F3978F8940984, 30, 28 }, - { 0xC097CE7BC90715B3, 56, 36 }, - { 0x8F7E32CE7BEA5C70, 83, 44 }, - { 0xD5D238A4ABE98068, 109, 52 }, - { 0x9F4F2726179A2245, 136, 60 }, - { 0xED63A231D4C4FB27, 162, 68 }, - { 0xB0DE65388CC8ADA8, 189, 76 }, - { 0x83C7088E1AAB65DB, 216, 84 }, - { 0xC45D1DF942711D9A, 242, 92 }, - { 0x924D692CA61BE758, 269, 100 }, - { 0xDA01EE641A708DEA, 295, 108 }, - { 0xA26DA3999AEF774A, 322, 116 }, - { 0xF209787BB47D6B85, 348, 124 }, - { 0xB454E4A179DD1877, 375, 132 }, - { 0x865B86925B9BC5C2, 402, 140 }, - { 0xC83553C5C8965D3D, 428, 148 }, - { 0x952AB45CFA97A0B3, 455, 156 }, - { 0xDE469FBD99A05FE3, 481, 164 }, - { 0xA59BC234DB398C25, 508, 172 }, - { 0xF6C69A72A3989F5C, 534, 180 }, - { 0xB7DCBF5354E9BECE, 561, 188 }, - { 0x88FCF317F22241E2, 588, 196 }, - { 0xCC20CE9BD35C78A5, 614, 204 }, - { 0x98165AF37B2153DF, 641, 212 }, - { 0xE2A0B5DC971F303A, 667, 220 }, - { 0xA8D9D1535CE3B396, 694, 228 }, - { 0xFB9B7CD9A4A7443C, 720, 236 }, - { 0xBB764C4CA7A44410, 747, 244 }, - { 0x8BAB8EEFB6409C1A, 774, 252 }, - { 0xD01FEF10A657842C, 800, 260 }, - { 0x9B10A4E5E9913129, 827, 268 }, - { 0xE7109BFBA19C0C9D, 853, 276 }, - { 0xAC2820D9623BF429, 880, 284 }, - { 0x80444B5E7AA7CF85, 907, 292 }, - { 0xBF21E44003ACDD2D, 933, 300 }, - { 0x8E679C2F5E44FF8F, 960, 308 }, - { 0xD433179D9C8CB841, 986, 316 }, - { 0x9E19DB92B4E31BA9, 1013, 324 }, - }; - - // This computation gives exactly the same results for k as - // k = ceil((kAlpha - e - 1) * 0.30102999566398114) - // for |e| <= 1500, but doesn't require floating-point operations. - // NB: log_10(2) ~= 78913 / 2^18 - assert(e >= -1500); - assert(e <= 1500); - const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + (f > 0); - - const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - assert(index >= 0); - assert(index < kCachedPowersSize); - static_cast(kCachedPowersSize); // Fix warning. - - const cached_power cached = kCachedPowers[index]; - assert(kAlpha <= cached.e + e + 64); - assert(kGamma >= cached.e + e + 64); - - return cached; -} - -/*! -For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. -For n == 0, returns 1 and sets pow10 := 1. -*/ -inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) -{ - // LCOV_EXCL_START - if (n >= 1000000000) - { - pow10 = 1000000000; - return 10; - } - // LCOV_EXCL_STOP - else if (n >= 100000000) - { - pow10 = 100000000; - return 9; - } - else if (n >= 10000000) - { - pow10 = 10000000; - return 8; - } - else if (n >= 1000000) - { - pow10 = 1000000; - return 7; - } - else if (n >= 100000) - { - pow10 = 100000; - return 6; - } - else if (n >= 10000) - { - pow10 = 10000; - return 5; - } - else if (n >= 1000) - { - pow10 = 1000; - return 4; - } - else if (n >= 100) - { - pow10 = 100; - return 3; - } - else if (n >= 10) - { - pow10 = 10; - return 2; - } - else - { - pow10 = 1; - return 1; - } -} - -inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, - uint64_t rest, uint64_t ten_k) -{ - assert(len >= 1); - assert(dist <= delta); - assert(rest <= delta); - assert(ten_k > 0); - - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // ten_k - // <------> - // <---- rest ----> - // --------------[------------------+----+--------------]-------------- - // w V - // = buf * 10^k - // - // ten_k represents a unit-in-the-last-place in the decimal representation - // stored in buf. - // Decrement buf by ten_k while this takes buf closer to w. - - // The tests are written in this order to avoid overflow in unsigned - // integer arithmetic. - - while (rest < dist - and delta - rest >= ten_k - and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) - { - assert(buf[len - 1] != '0'); - buf[len - 1]--; - rest += ten_k; - } -} - -/*! -Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. -M- and M+ must be normalized and share the same exponent -60 <= e <= -32. -*/ -inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, - diyfp M_minus, diyfp w, diyfp M_plus) -{ - static_assert(kAlpha >= -60, "internal error"); - static_assert(kGamma <= -32, "internal error"); - - // Generates the digits (and the exponent) of a decimal floating-point - // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's - // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. - // - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // Grisu2 generates the digits of M+ from left to right and stops as soon as - // V is in [M-,M+]. - - assert(M_plus.e >= kAlpha); - assert(M_plus.e <= kGamma); - - uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) - uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) - - // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): - // - // M+ = f * 2^e - // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e - // = ((p1 ) * 2^-e + (p2 )) * 2^e - // = p1 + p2 * 2^e - - const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); - - uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) - uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e - - // 1) - // - // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - - assert(p1 > 0); - - uint32_t pow10; - const int k = find_largest_pow10(p1, pow10); - - // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) - // - // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) - // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) - // - // M+ = p1 + p2 * 2^e - // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e - // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e - // = d[k-1] * 10^(k-1) + ( rest) * 2^e - // - // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) - // - // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] - // - // but stop as soon as - // - // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e - - int n = k; - while (n > 0) - { - // Invariants: - // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) - // pow10 = 10^(n-1) <= p1 < 10^n - // - const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) - const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) - // - // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e - // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) - // - assert(d <= 9); - buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) - // - p1 = r; - n--; - // - // M+ = buffer * 10^n + (p1 + p2 * 2^e) - // pow10 = 10^n - // - - // Now check if enough digits have been generated. - // Compute - // - // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e - // - // Note: - // Since rest and delta share the same exponent e, it suffices to - // compare the significands. - const uint64_t rest = (uint64_t{p1} << -one.e) + p2; - if (rest <= delta) - { - // V = buffer * 10^n, with M- <= V <= M+. - - decimal_exponent += n; - - // We may now just stop. But instead look if the buffer could be - // decremented to bring V closer to w. - // - // pow10 = 10^n is now 1 ulp in the decimal representation V. - // The rounding procedure works with diyfp's with an implicit - // exponent of e. - // - // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e - // - const uint64_t ten_n = uint64_t{pow10} << -one.e; - grisu2_round(buffer, length, dist, delta, rest, ten_n); - - return; - } - - pow10 /= 10; - // - // pow10 = 10^(n-1) <= p1 < 10^n - // Invariants restored. - } - - // 2) - // - // The digits of the integral part have been generated: - // - // M+ = d[k-1]...d[1]d[0] + p2 * 2^e - // = buffer + p2 * 2^e - // - // Now generate the digits of the fractional part p2 * 2^e. - // - // Note: - // No decimal point is generated: the exponent is adjusted instead. - // - // p2 actually represents the fraction - // - // p2 * 2^e - // = p2 / 2^-e - // = d[-1] / 10^1 + d[-2] / 10^2 + ... - // - // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) - // - // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m - // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) - // - // using - // - // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) - // = ( d) * 2^-e + ( r) - // - // or - // 10^m * p2 * 2^e = d + r * 2^e - // - // i.e. - // - // M+ = buffer + p2 * 2^e - // = buffer + 10^-m * (d + r * 2^e) - // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e - // - // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - - assert(p2 > delta); - - int m = 0; - for (;;) - { - // Invariant: - // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e - // = buffer * 10^-m + 10^-m * (p2 ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e - // - assert(p2 <= UINT64_MAX / 10); - p2 *= 10; - const uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e - const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e - // - // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) - // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - assert(d <= 9); - buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - p2 = r; - m++; - // - // M+ = buffer * 10^-m + 10^-m * p2 * 2^e - // Invariant restored. - - // Check if enough digits have been generated. - // - // 10^-m * p2 * 2^e <= delta * 2^e - // p2 * 2^e <= 10^m * delta * 2^e - // p2 <= 10^m * delta - delta *= 10; - dist *= 10; - if (p2 <= delta) - { - break; - } - } - - // V = buffer * 10^-m, with M- <= V <= M+. - - decimal_exponent -= m; - - // 1 ulp in the decimal representation is now 10^-m. - // Since delta and dist are now scaled by 10^m, we need to do the - // same with ulp in order to keep the units in sync. - // - // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e - // - const uint64_t ten_m = one.f; - grisu2_round(buffer, length, dist, delta, p2, ten_m); - - // By construction this algorithm generates the shortest possible decimal - // number (Loitsch, Theorem 6.2) which rounds back to w. - // For an input number of precision p, at least - // - // N = 1 + ceil(p * log_10(2)) - // - // decimal digits are sufficient to identify all binary floating-point - // numbers (Matula, "In-and-Out conversions"). - // This implies that the algorithm does not produce more than N decimal - // digits. - // - // N = 17 for p = 53 (IEEE double precision) - // N = 9 for p = 24 (IEEE single precision) -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -inline void grisu2(char* buf, int& len, int& decimal_exponent, - diyfp m_minus, diyfp v, diyfp m_plus) -{ - assert(m_plus.e == m_minus.e); - assert(m_plus.e == v.e); - - // --------(-----------------------+-----------------------)-------- (A) - // m- v m+ - // - // --------------------(-----------+-----------------------)-------- (B) - // m- v m+ - // - // First scale v (and m- and m+) such that the exponent is in the range - // [alpha, gamma]. - - const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); - - const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k - - // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] - const diyfp w = diyfp::mul(v, c_minus_k); - const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); - const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); - - // ----(---+---)---------------(---+---)---------------(---+---)---- - // w- w w+ - // = c*m- = c*v = c*m+ - // - // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and - // w+ are now off by a small amount. - // In fact: - // - // w - v * 10^k < 1 ulp - // - // To account for this inaccuracy, add resp. subtract 1 ulp. - // - // --------+---[---------------(---+---)---------------]---+-------- - // w- M- w M+ w+ - // - // Now any number in [M-, M+] (bounds included) will round to w when input, - // regardless of how the input rounding algorithm breaks ties. - // - // And digit_gen generates the shortest possible such number in [M-, M+]. - // Note that this does not mean that Grisu2 always generates the shortest - // possible number in the interval (m-, m+). - const diyfp M_minus(w_minus.f + 1, w_minus.e); - const diyfp M_plus (w_plus.f - 1, w_plus.e ); - - decimal_exponent = -cached.k; // = -(-k) = k - - grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -template -void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) -{ - static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, - "internal error: not enough precision"); - - assert(std::isfinite(value)); - assert(value > 0); - - // If the neighbors (and boundaries) of 'value' are always computed for double-precision - // numbers, all float's can be recovered using strtod (and strtof). However, the resulting - // decimal representations are not exactly "short". - // - // The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) - // says "value is converted to a string as if by std::sprintf in the default ("C") locale" - // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' - // does. - // On the other hand, the documentation for 'std::to_chars' requires that "parsing the - // representation using the corresponding std::from_chars function recovers value exactly". That - // indicates that single precision floating-point numbers should be recovered using - // 'std::strtof'. - // - // NB: If the neighbors are computed for single-precision numbers, there is a single float - // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision - // value is off by 1 ulp. -#if 0 - const boundaries w = compute_boundaries(static_cast(value)); -#else - const boundaries w = compute_boundaries(value); -#endif - - grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); -} - -/*! -@brief appends a decimal representation of e to buf -@return a pointer to the element following the exponent. -@pre -1000 < e < 1000 -*/ -inline char* append_exponent(char* buf, int e) -{ - assert(e > -1000); - assert(e < 1000); - - if (e < 0) - { - e = -e; - *buf++ = '-'; - } - else - { - *buf++ = '+'; - } - - uint32_t k = static_cast(e); - if (k < 10) - { - // Always print at least two digits in the exponent. - // This is for compatibility with printf("%g"). - *buf++ = '0'; - *buf++ = static_cast('0' + k); - } - else if (k < 100) - { - *buf++ = static_cast('0' + k / 10); - k %= 10; - *buf++ = static_cast('0' + k); - } - else - { - *buf++ = static_cast('0' + k / 100); - k %= 100; - *buf++ = static_cast('0' + k / 10); - k %= 10; - *buf++ = static_cast('0' + k); - } - - return buf; -} - -/*! -@brief prettify v = buf * 10^decimal_exponent - -If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point -notation. Otherwise it will be printed in exponential notation. - -@pre min_exp < 0 -@pre max_exp > 0 -*/ -inline char* format_buffer(char* buf, int len, int decimal_exponent, - int min_exp, int max_exp) -{ - assert(min_exp < 0); - assert(max_exp > 0); - - const int k = len; - const int n = len + decimal_exponent; - - // v = buf * 10^(n-k) - // k is the length of the buffer (number of decimal digits) - // n is the position of the decimal point relative to the start of the buffer. - - if (k <= n and n <= max_exp) - { - // digits[000] - // len <= max_exp + 2 - - std::memset(buf + k, '0', static_cast(n - k)); - // Make it look like a floating-point number (#362, #378) - buf[n + 0] = '.'; - buf[n + 1] = '0'; - return buf + (n + 2); - } - - if (0 < n and n <= max_exp) - { - // dig.its - // len <= max_digits10 + 1 - - assert(k > n); - - std::memmove(buf + (n + 1), buf + n, static_cast(k - n)); - buf[n] = '.'; - return buf + (k + 1); - } - - if (min_exp < n and n <= 0) - { - // 0.[000]digits - // len <= 2 + (-min_exp - 1) + max_digits10 - - std::memmove(buf + (2 + -n), buf, static_cast(k)); - buf[0] = '0'; - buf[1] = '.'; - std::memset(buf + 2, '0', static_cast(-n)); - return buf + (2 + (-n) + k); - } - - if (k == 1) - { - // dE+123 - // len <= 1 + 5 - - buf += 1; - } - else - { - // d.igitsE+123 - // len <= max_digits10 + 1 + 5 - - std::memmove(buf + 2, buf + 1, static_cast(k - 1)); - buf[1] = '.'; - buf += 1 + k; - } - - *buf++ = 'e'; - return append_exponent(buf, n - 1); -} - -} // namespace dtoa_impl - -/*! -@brief generates a decimal representation of the floating-point number value in [first, last). - -The format of the resulting decimal representation is similar to printf's %g -format. Returns an iterator pointing past-the-end of the decimal representation. - -@note The input number must be finite, i.e. NaN's and Inf's are not supported. -@note The buffer must be large enough. -@note The result is NOT null-terminated. -*/ -template -char* to_chars(char* first, char* last, FloatType value) -{ - static_cast(last); // maybe unused - fix warning - assert(std::isfinite(value)); - - // Use signbit(value) instead of (value < 0) since signbit works for -0. - if (std::signbit(value)) - { - value = -value; - *first++ = '-'; - } - - if (value == 0) // +-0 - { - *first++ = '0'; - // Make it look like a floating-point number (#362, #378) - *first++ = '.'; - *first++ = '0'; - return first; - } - - assert(last - first >= std::numeric_limits::max_digits10); - - // Compute v = buffer * 10^decimal_exponent. - // The decimal digits are stored in the buffer, which needs to be interpreted - // as an unsigned decimal integer. - // len is the length of the buffer, i.e. the number of decimal digits. - int len = 0; - int decimal_exponent = 0; - dtoa_impl::grisu2(first, len, decimal_exponent, value); - - assert(len <= std::numeric_limits::max_digits10); - - // Format the buffer like printf("%.*g", prec, value) - constexpr int kMinExp = -4; - // Use digits10 here to increase compatibility with version 2. - constexpr int kMaxExp = std::numeric_limits::digits10; - - assert(last - first >= kMaxExp + 2); - assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); - assert(last - first >= std::numeric_limits::max_digits10 + 6); - - return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); -} - -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// serialization // -/////////////////// - -template -class serializer -{ - using string_t = typename BasicJsonType::string_t; - using number_float_t = typename BasicJsonType::number_float_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - static constexpr uint8_t UTF8_ACCEPT = 0; - static constexpr uint8_t UTF8_REJECT = 1; - - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - */ - serializer(output_adapter_t s, const char ichar) - : o(std::move(s)), loc(std::localeconv()), - thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), - decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), - indent_char(ichar), indent_string(512, indent_char) - {} - - // delete because of pointer members - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const BasicJsonType& val, const bool pretty_print, - const bool ensure_ascii, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_type) - { - case value_t::object: - { - if (val.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } - - case value_t::array: - { - if (val.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(not val.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - dump(*i, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } - - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_value.string, ensure_ascii); - o->write_character('\"'); - return; - } - - case value_t::boolean: - { - if (val.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } - - case value_t::number_integer: - { - dump_integer(val.m_value.number_integer); - return; - } - - case value_t::number_unsigned: - { - dump_integer(val.m_value.number_unsigned); - return; - } - - case value_t::number_float: - { - dump_float(val.m_value.number_float); - return; - } - - case value_t::discarded: - { - o->write_characters("", 11); - return; - } - - case value_t::null: - { - o->write_characters("null", 4); - return; - } - } - } - - private: - /*! - @brief dump escaped string - - Escape a string by replacing certain special characters by a sequence of an - escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s, const bool ensure_ascii) - { - uint32_t codepoint; - uint8_t state = UTF8_ACCEPT; - std::size_t bytes = 0; // number of bytes written to string_buffer - - for (std::size_t i = 0; i < s.size(); ++i) - { - const auto byte = static_cast(s[i]); - - switch (decode(state, codepoint, byte)) - { - case UTF8_ACCEPT: // decode found a new code point - { - switch (codepoint) - { - case 0x08: // backspace - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'b'; - break; - } - - case 0x09: // horizontal tab - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 't'; - break; - } - - case 0x0A: // newline - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'n'; - break; - } - - case 0x0C: // formfeed - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'f'; - break; - } - - case 0x0D: // carriage return - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'r'; - break; - } - - case 0x22: // quotation mark - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\"'; - break; - } - - case 0x5C: // reverse solidus - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\\'; - break; - } - - default: - { - // escape control characters (0x00..0x1F) or, if - // ensure_ascii parameter is used, non-ASCII characters - if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) - { - if (codepoint <= 0xFFFF) - { - std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", - static_cast(codepoint)); - bytes += 6; - } - else - { - std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", - static_cast(0xD7C0 + (codepoint >> 10)), - static_cast(0xDC00 + (codepoint & 0x3FF))); - bytes += 12; - } - } - else - { - // copy byte to buffer (all previous bytes - // been copied have in default case above) - string_buffer[bytes++] = s[i]; - } - break; - } - } - - // write buffer and reset index; there must be 13 bytes - // left, as this is the maximal number of bytes to be - // written ("\uxxxx\uxxxx\0") for one code point - if (string_buffer.size() - bytes < 13) - { - o->write_characters(string_buffer.data(), bytes); - bytes = 0; - } - break; - } - - case UTF8_REJECT: // decode found invalid UTF-8 byte - { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); - } - - default: // decode found yet incomplete multi-byte code point - { - if (not ensure_ascii) - { - // code point will not be escaped - copy byte to buffer - string_buffer[bytes++] = s[i]; - } - break; - } - } - } - - if (JSON_LIKELY(state == UTF8_ACCEPT)) - { - // write buffer - if (bytes > 0) - { - o->write_characters(string_buffer.data(), bytes); - } - } - else - { - // we finish reading, but do not accept: string was incomplete - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); - } - } - - /*! - @brief dump an integer - - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. - - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template::value or - std::is_same::value, - int> = 0> - void dump_integer(NumberType x) - { - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } - - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 - std::size_t i = 0; - - while (x != 0) - { - // spare 1 byte for '\0' - assert(i < number_buffer.size() - 1); - - const auto digit = std::labs(static_cast(x % 10)); - number_buffer[i++] = static_cast('0' + digit); - x /= 10; - } - - if (is_negative) - { - // make sure there is capacity for the '-' - assert(i < number_buffer.size() - 2); - number_buffer[i++] = '-'; - } - - std::reverse(number_buffer.begin(), number_buffer.begin() + i); - o->write_characters(number_buffer.data(), i); - } - - /*! - @brief dump a floating-point number - - Dump a given floating-point number to output stream @a o. Works internally - with @a number_buffer. - - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) - { - // NaN / inf - if (not std::isfinite(x)) - { - o->write_characters("null", 4); - return; - } - - // If number_float_t is an IEEE-754 single or double precision number, - // use the Grisu2 algorithm to produce short numbers which are - // guaranteed to round-trip, using strtof and strtod, resp. - // - // NB: The test below works if == . - static constexpr bool is_ieee_single_or_double - = (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 24 and std::numeric_limits::max_exponent == 128) or - (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 53 and std::numeric_limits::max_exponent == 1024); - - dump_float(x, std::integral_constant()); - } - - void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) - { - char* begin = number_buffer.data(); - char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); - - o->write_characters(begin, static_cast(end - begin)); - } - - void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) - { - // get number of digits for a float -> text -> float round-trip - static constexpr auto d = std::numeric_limits::max_digits10; - - // the actual conversion - std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - - // negative value indicates an error - assert(len > 0); - // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); - - // erase thousands separator - if (thousands_sep != '\0') - { - const auto end = std::remove(number_buffer.begin(), - number_buffer.begin() + len, thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } - - // convert decimal point to '.' - if (decimal_point != '\0' and decimal_point != '.') - { - const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); - if (dec_pos != number_buffer.end()) - { - *dec_pos = '.'; - } - } - - o->write_characters(number_buffer.data(), static_cast(len)); - - // determine if need to append ".0" - const bool value_is_int_like = - std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, - [](char c) - { - return (c == '.' or c == 'e'); - }); - - if (value_is_int_like) - { - o->write_characters(".0", 2); - } - } - - /*! - @brief check whether a string is UTF-8 encoded - - The function checks each byte of a string whether it is UTF-8 encoded. The - result of the check is stored in the @a state parameter. The function must - be called initially with state 0 (accept). State 1 means the string must - be rejected, because the current byte is not allowed. If the string is - completely processed, but the state is non-zero, the string ended - prematurely; that is, the last byte indicated more bytes should have - followed. - - @param[in,out] state the state of the decoding - @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) - @param[in] byte next byte to decode - @return new state - - @note The function has been edited: a std::array is used. - - @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann - @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - */ - static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept - { - static const std::array utf8d = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..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, // 20..3F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF - 8, 8, 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, // C0..DF - 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF - 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 - } - }; - - const uint8_t type = utf8d[byte]; - - codep = (state != UTF8_ACCEPT) - ? (byte & 0x3fu) | (codep << 6) - : static_cast(0xff >> type) & (byte); - - state = utf8d[256u + state * 16u + type]; - return state; - } - - private: - /// the output of the serializer - output_adapter_t o = nullptr; - - /// a (hopefully) large enough character buffer - std::array number_buffer{{}}; - - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; - - /// string buffer - std::array string_buffer{{}}; - - /// the indentation character - const char indent_char; - /// the indentation string - string_t indent_string; -}; -} -} - -// #include - - -#include -#include - -namespace nlohmann -{ -namespace detail -{ -template -class json_ref -{ - public: - using value_type = BasicJsonType; - - json_ref(value_type&& value) - : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) - {} - - json_ref(const value_type& value) - : value_ref(const_cast(&value)), is_rvalue(false) - {} - - json_ref(std::initializer_list init) - : owned_value(init), value_ref(&owned_value), is_rvalue(true) - {} - - template - json_ref(Args&& ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) - {} - - // class should be movable only - json_ref(json_ref&&) = default; - json_ref(const json_ref&) = delete; - json_ref& operator=(const json_ref&) = delete; - - value_type moved_or_copied() const - { - if (is_rvalue) - { - return std::move(*value_ref); - } - return *value_ref; - } - - value_type const& operator*() const - { - return *static_cast(value_ref); - } - - value_type const* operator->() const - { - return static_cast(value_ref); - } - - private: - mutable value_type owned_value = nullptr; - value_type* value_ref = nullptr; - const bool is_rvalue; -}; -} -} - -// #include - - -#include // assert -#include // accumulate -#include // string -#include // vector - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -template -class json_pointer -{ - // allow basic_json to access private members - NLOHMANN_BASIC_JSON_TPL_DECLARATION - friend class basic_json; - - public: - /*! - @brief create JSON pointer - - Create a JSON pointer according to the syntax described in - [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). - - @param[in] s string representing the JSON pointer; if omitted, the empty - string is assumed which references the whole JSON value - - @throw parse_error.107 if the given JSON pointer @a s is nonempty and does - not begin with a slash (`/`); see example below - - @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is - not followed by `0` (representing `~`) or `1` (representing `/`); see - example below - - @liveexample{The example shows the construction several valid JSON pointers - as well as the exceptional behavior.,json_pointer} - - @since version 2.0.0 - */ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} - - /*! - @brief return a string representation of the JSON pointer - - @invariant For each JSON pointer `ptr`, it holds: - @code {.cpp} - ptr == json_pointer(ptr.to_string()); - @endcode - - @return a string representation of the JSON pointer - - @liveexample{The example shows the result of `to_string`., - json_pointer__to_string} - - @since version 2.0.0 - */ - std::string to_string() const noexcept - { - return std::accumulate(reference_tokens.begin(), reference_tokens.end(), - std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); - } - - /// @copydoc to_string() - operator std::string() const - { - return to_string(); - } - - /*! - @param[in] s reference token to be converted into an array index - - @return integer representation of @a s - - @throw out_of_range.404 if string @a s could not be converted to an integer - */ - static int array_index(const std::string& s) - { - std::size_t processed_chars = 0; - const int res = std::stoi(s, &processed_chars); - - // check if the string was completely read - if (JSON_UNLIKELY(processed_chars != s.size())) - { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); - } - - return res; - } - - private: - /*! - @brief remove and return last reference pointer - @throw out_of_range.405 if JSON pointer has no parent - */ - std::string pop_back() - { - if (JSON_UNLIKELY(is_root())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); - } - - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; - } - - /// return whether pointer points to the root document - bool is_root() const - { - return reference_tokens.empty(); - } - - json_pointer top() const - { - if (JSON_UNLIKELY(is_root())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - - @throw parse_error.109 if array index is not a number - @throw type_error.313 if value cannot be unflattened - */ - BasicJsonType& get_and_create(BasicJsonType& j) const - { - using size_type = typename BasicJsonType::size_type; - auto result = &j; - - // in case no reference tokens exist, return a reference to the JSON value - // j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->m_type) - { - case detail::value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case detail::value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // create an entry in the array - JSON_TRY - { - result = &result->operator[](static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - /* - The following code is only reached if there exists a reference - token _and_ the current value is primitive. In this case, we have - an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. - */ - default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); - } - } - - return *result; - } - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries to - create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - BasicJsonType& get_unchecked(BasicJsonType* ptr) const - { - using size_type = typename BasicJsonType::size_type; - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->m_type == detail::value_t::null) - { - // check if reference token is a number - const bool nums = - std::all_of(reference_token.begin(), reference_token.end(), - [](const char x) - { - return (x >= '0' and x <= '9'); - }); - - // change value to array for numbers or "-" or to object otherwise - *ptr = (nums or reference_token == "-") - ? detail::value_t::array - : detail::value_t::object; - } - - switch (ptr->m_type) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - BasicJsonType& get_checked(BasicJsonType* ptr) const - { - using size_type = typename BasicJsonType::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; - } - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const - { - using size_type = typename BasicJsonType::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // use unchecked array access - JSON_TRY - { - ptr = &ptr->operator[]( - static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const BasicJsonType& get_checked(const BasicJsonType* ptr) const - { - using size_type = typename BasicJsonType::size_type; - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, - "array index '" + reference_token + - "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(array_index(reference_token))); - } - JSON_CATCH(std::invalid_argument&) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - - return *ptr; - } - - /*! - @brief split the string input to reference tokens - - @note This function is only called by the json_pointer constructor. - All exceptions below are documented there. - - @throw parse_error.107 if the pointer is not empty or begins with '/' - @throw parse_error.108 if character '~' is not followed by '0' or '1' - */ - static std::vector split(const std::string& reference_string) - { - std::vector result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (JSON_UNLIKELY(reference_string[0] != '/')) - { - JSON_THROW(detail::parse_error::create(107, 1, - "JSON pointer must be empty or begin with '/' - was: '" + - reference_string + "'")); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - std::size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (std::size_t pos = reference_token.find_first_of('~'); - pos != std::string::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - assert(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (JSON_UNLIKELY(pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and - reference_token[pos + 1] != '1'))) - { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); - } - } - - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - /*! - @brief replace all occurrences of a substring by another string - - @param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t - @param[in] f the substring to replace with @a t - @param[in] t the string to replace @a f - - @pre The search string @a f must not be empty. **This precondition is - enforced with an assertion.** - - @since version 2.0.0 - */ - static void replace_substring(std::string& s, const std::string& f, - const std::string& t) - { - assert(not f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} - } - - /// escape "~"" to "~0" and "/" to "~1" - static std::string escape(std::string s) - { - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; - } - - /// unescape "~1" to tilde and "~0" to slash (order is important!) - static void unescape(std::string& s) - { - replace_substring(s, "~1", "/"); - replace_substring(s, "~0", "~"); - } - - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - static void flatten(const std::string& reference_string, - const BasicJsonType& value, - BasicJsonType& result) - { - switch (value.m_type) - { - case detail::value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (std::size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } - - case detail::value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + escape(element.first), element.second, result); - } - } - break; - } - - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - - @throw parse_error.109 if array index is not a number - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - @throw type_error.313 if value cannot be unflattened - */ - static BasicJsonType - unflatten(const BasicJsonType& value) - { - if (JSON_UNLIKELY(not value.is_object())) - { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); - } - - BasicJsonType result; - - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (JSON_UNLIKELY(not element.second.is_primitive())) - { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); - } - - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; - } - - friend bool operator==(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return (lhs.reference_tokens == rhs.reference_tokens); - } - - friend bool operator!=(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return not (lhs == rhs); - } - - /// the reference tokens - std::vector reference_tokens; -}; -} - -// #include - - -#include - -// #include - -// #include - - -namespace nlohmann -{ -template -struct adl_serializer -{ - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - { - ::nlohmann::to_json(j, std::forward(val)); - } -}; -} - - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ - -/*! -@brief a class to store JSON values - -@tparam ObjectType type for JSON objects (`std::map` by default; will be used -in @ref object_t) -@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used -in @ref array_t) -@tparam StringType type for JSON strings and object keys (`std::string` by -default; will be used in @ref string_t) -@tparam BooleanType type for JSON booleans (`bool` by default; will be used -in @ref boolean_t) -@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by -default; will be used in @ref number_integer_t) -@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c -`uint64_t` by default; will be used in @ref number_unsigned_t) -@tparam NumberFloatType type for JSON floating-point numbers (`double` by -default; will be used in @ref number_float_t) -@tparam AllocatorType type of the allocator to use (`std::allocator` by -default) -@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` -and `from_json()` (@ref adl_serializer by default) - -@requirement The class satisfies the following concept requirements: -- Basic - - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): - JSON values can be default constructed. The result will be a JSON null - value. - - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): - A JSON value can be constructed from an rvalue argument. - - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constructed from an lvalue expression. - - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): - A JSON value van be assigned from an rvalue argument. - - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): - A JSON value can be copy-assigned from an lvalue expression. - - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): - JSON values can be destructed. -- Layout - - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): - JSON values have - [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): - All non-static data members are private and standard layout types, the - class has no virtual functions or (virtual) base classes. -- Library-wide - - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): - JSON values can be compared with `==`, see @ref - operator==(const_reference,const_reference). - - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): - JSON values can be compared with `<`, see @ref - operator<(const_reference,const_reference). - - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): - Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of - other compatible types, using unqualified function call @ref swap(). - - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): - JSON values can be compared against `std::nullptr_t` objects which are used - to model the `null` value. -- Container - - [Container](http://en.cppreference.com/w/cpp/concept/Container): - JSON values can be used like STL containers and provide iterator access. - - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); - JSON values can be used like STL containers and provide reverse iterator - access. - -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@internal -@note ObjectType trick from http://stackoverflow.com/a/9860911 -@endinternal - -@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange -Format](http://rfc7159.net/rfc7159) - -@since version 1.0.0 - -@nosubgrouping -*/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -class basic_json -{ - private: - template friend struct detail::external_constructor; - friend ::nlohmann::json_pointer; - friend ::nlohmann::detail::parser; - friend ::nlohmann::detail::serializer; - template - friend class ::nlohmann::detail::iter_impl; - template - friend class ::nlohmann::detail::binary_writer; - template - friend class ::nlohmann::detail::binary_reader; - - /// workaround type for MSVC - using basic_json_t = NLOHMANN_BASIC_JSON_TPL; - - // convenience aliases for types residing in namespace detail; - using lexer = ::nlohmann::detail::lexer; - using parser = ::nlohmann::detail::parser; - - using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; - template - using internal_iterator = ::nlohmann::detail::internal_iterator; - template - using iter_impl = ::nlohmann::detail::iter_impl; - template - using iteration_proxy = ::nlohmann::detail::iteration_proxy; - template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; - - template - using output_adapter_t = ::nlohmann::detail::output_adapter_t; - - using binary_reader = ::nlohmann::detail::binary_reader; - template using binary_writer = ::nlohmann::detail::binary_writer; - - using serializer = ::nlohmann::detail::serializer; - - public: - using value_t = detail::value_t; - /// @copydoc nlohmann::json_pointer - using json_pointer = ::nlohmann::json_pointer; - template - using json_serializer = JSONSerializer; - /// helper type for initializer lists of basic_json values - using initializer_list_t = std::initializer_list>; - - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - /// @copydoc detail::exception - using exception = detail::exception; - /// @copydoc detail::parse_error - using parse_error = detail::parse_error; - /// @copydoc detail::invalid_iterator - using invalid_iterator = detail::invalid_iterator; - /// @copydoc detail::type_error - using type_error = detail::type_error; - /// @copydoc detail::out_of_range - using out_of_range = detail::out_of_range; - /// @copydoc detail::other_error - using other_error = detail::other_error; - - /// @} - - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType; - - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl; - /// a const iterator for a basic_json container - using const_iterator = iter_impl; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; - - /// @} - - - /*! - @brief returns the allocator associated with the container - */ - static allocator_type get_allocator() - { - return allocator_type(); - } - - /*! - @brief returns version information on the library - - This function returns a JSON object with information about the library, - including the version number and information on the platform and compiler. - - @return JSON object holding version information - key | description - ----------- | --------------- - `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). - `copyright` | The copyright line for the library as string. - `name` | The name of the library as string. - `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. - `url` | The URL of the project as string. - `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). - - @liveexample{The following code shows an example output of the `meta()` - function.,meta} - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @complexity Constant. - - @since 2.1.0 - */ - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2017 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"]["string"] = - std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + - std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + - std::to_string(NLOHMANN_JSON_VERSION_PATCH); - result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; - result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; - result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif - -#if defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif - -#ifdef __cplusplus - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } - - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - -#if defined(JSON_HAS_CPP_14) - // Use transparent comparator if possible, combined with perfect forwarding - // on find() and count() calls prevents unnecessary string construction. - using object_comparator_t = std::less<>; -#else - using object_comparator_t = std::less; -#endif - - /*! - @brief a type for an object - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: - > An object is an unordered collection of zero or more name/value pairs, - > where a name is a string and a value is a string, number, boolean, null, - > object, or array. - - To store objects in C++, a type is defined by the template parameters - described below. - - @tparam ObjectType the container to store objects (e.g., `std::map` or - `std::unordered_map`) - @tparam StringType the type of the keys or names (e.g., `std::string`). - The comparison function `std::less` is used to order elements - inside the container. - @tparam AllocatorType the allocator to use for objects (e.g., - `std::allocator`) - - #### Default type - - With the default values for @a ObjectType (`std::map`), @a StringType - (`std::string`), and @a AllocatorType (`std::allocator`), the default - value for @a object_t is: - - @code {.cpp} - std::map< - std::string, // key_type - basic_json, // value_type - std::less, // key_compare - std::allocator> // allocator_type - > - @endcode - - #### Behavior - - The choice of @a object_t influences the behavior of the JSON class. With - the default type, objects have the following behavior: - - - When all names are unique, objects will be interoperable in the sense - that all software implementations receiving that object will agree on - the name-value mappings. - - When the names within an object are not unique, it is unspecified which - one of the values for a given key will be chosen. For instance, - `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or - `{"key": 2}`. - - Internally, name/value pairs are stored in lexicographical order of the - names. Objects will also be serialized (see @ref dump) in this order. - For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored - and serialized as `{"a": 2, "b": 1}`. - - When comparing objects, the order of the name/value pairs is irrelevant. - This makes objects interoperable in the sense that they will not be - affected by these differences. For instance, `{"b": 1, "a": 2}` and - `{"a": 2, "b": 1}` will be treated as equal. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the object's limit of nesting is not explicitly constrained. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON object. - - #### Storage - - Objects are stored as pointers in a @ref basic_json type. That is, for any - access to object values, a pointer of type `object_t*` must be - dereferenced. - - @sa @ref array_t -- type for an array value - - @since version 1.0.0 - - @note The order name/value pairs are added to the object is *not* - preserved by the library. Therefore, iterating an object may return - name/value pairs in a different order than they were originally stored. In - fact, keys will be traversed in alphabetical order as `std::map` with - `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the - specified "unordered" nature of JSON objects. - */ - using object_t = ObjectType>>; - - /*! - @brief a type for an array - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: - > An array is an ordered sequence of zero or more values. - - To store objects in C++, a type is defined by the template parameters - explained below. - - @tparam ArrayType container type to store arrays (e.g., `std::vector` or - `std::list`) - @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) - - #### Default type - - With the default values for @a ArrayType (`std::vector`) and @a - AllocatorType (`std::allocator`), the default value for @a array_t is: - - @code {.cpp} - std::vector< - basic_json, // value_type - std::allocator // allocator_type - > - @endcode - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the array's limit of nesting is not explicitly constrained. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON array. - - #### Storage - - Arrays are stored as pointers in a @ref basic_json type. That is, for any - access to array values, a pointer of type `array_t*` must be dereferenced. - - @sa @ref object_t -- type for an object value - - @since version 1.0.0 - */ - using array_t = ArrayType>; - - /*! - @brief a type for a string - - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: - > A string is a sequence of zero or more Unicode characters. - - To store objects in C++, a type is defined by the template parameter - described below. Unicode values are split by the JSON class into - byte-sized characters during deserialization. - - @tparam StringType the container to store strings (e.g., `std::string`). - Note this container is used for keys/names in objects, see @ref object_t. - - #### Default type - - With the default values for @a StringType (`std::string`), the default - value for @a string_t is: - - @code {.cpp} - std::string - @endcode - - #### Encoding - - Strings are stored in UTF-8 encoding. Therefore, functions like - `std::string::size()` or `std::string::length()` return the number of - bytes in the string rather than the number of characters or glyphs. - - #### String comparison - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > Software implementations are typically required to test names of object - > members for equality. Implementations that transform the textual - > representation into sequences of Unicode code units and then perform the - > comparison numerically, code unit by code unit, are interoperable in the - > sense that implementations will agree in all cases on equality or - > inequality of two strings. For example, implementations that compare - > strings with escaped characters unconverted may incorrectly find that - > `"a\\b"` and `"a\u005Cb"` are not equal. - - This implementation is interoperable as it does compare strings code unit - by code unit. - - #### Storage - - String values are stored as pointers in a @ref basic_json type. That is, - for any access to string values, a pointer of type `string_t*` must be - dereferenced. - - @since version 1.0.0 - */ - using string_t = StringType; - - /*! - @brief a type for a boolean - - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a - type which differentiates the two literals `true` and `false`. - - To store objects in C++, a type is defined by the template parameter @a - BooleanType which chooses the type to use. - - #### Default type - - With the default values for @a BooleanType (`bool`), the default value for - @a boolean_t is: - - @code {.cpp} - bool - @endcode - - #### Storage - - Boolean values are stored directly inside a @ref basic_json type. - - @since version 1.0.0 - */ - using boolean_t = BooleanType; - - /*! - @brief a type for a number (integer) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store integer numbers in C++, a type is defined by the template - parameter @a NumberIntegerType which chooses the type to use. - - #### Default type - - With the default values for @a NumberIntegerType (`int64_t`), the default - value for @a number_integer_t is: - - @code {.cpp} - int64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `9223372036854775807` (INT64_MAX) and the minimal integer number - that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers - that are out of range will yield over/underflow when used in a - constructor. During deserialization, too large or small integer numbers - will be automatically be stored as @ref number_unsigned_t or @ref - number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange of the exactly supported range [INT64_MIN, - INT64_MAX], this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_integer_t = NumberIntegerType; - - /*! - @brief a type for a number (unsigned) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store unsigned integer numbers in C++, a type is defined by the - template parameter @a NumberUnsignedType which chooses the type to use. - - #### Default type - - With the default values for @a NumberUnsignedType (`uint64_t`), the - default value for @a number_unsigned_t is: - - @code {.cpp} - uint64_t - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. - - When the default type is used, the maximal integer number that can be - stored is `18446744073709551615` (UINT64_MAX) and the minimal integer - number that can be stored is `0`. Integer numbers that are out of range - will yield over/underflow when used in a constructor. During - deserialization, too large or small integer numbers will be automatically - be stored as @ref number_integer_t or @ref number_float_t. - - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. - - As this range is a subrange (when considered in conjunction with the - number_integer_t type) of the exactly supported range [0, UINT64_MAX], - this class's integer type is interoperable. - - #### Storage - - Integer number values are stored directly inside a @ref basic_json type. - - @sa @ref number_float_t -- type for number values (floating-point) - @sa @ref number_integer_t -- type for number values (integer) - - @since version 2.0.0 - */ - using number_unsigned_t = NumberUnsignedType; - - /*! - @brief a type for a number (floating-point) - - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. - - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. - - To store floating-point numbers in C++, a type is defined by the template - parameter @a NumberFloatType which chooses the type to use. - - #### Default type - - With the default values for @a NumberFloatType (`double`), the default - value for @a number_float_t is: - - @code {.cpp} - double - @endcode - - #### Default behavior - - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in floating-point literals will be ignored. Internally, - the value will be stored as decimal number. For instance, the C++ - floating-point literal `01.2` will be serialized to `1.2`. During - deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) states: - > This specification allows implementations to set limits on the range and - > precision of numbers accepted. Since software that implements IEEE - > 754-2008 binary64 (double precision) numbers is generally available and - > widely used, good interoperability can be achieved by implementations - > that expect no more precision or range than these provide, in the sense - > that implementations will approximate JSON numbers within the expected - > precision. - - This implementation does exactly follow this approach, as it uses double - precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` - will be stored as NaN internally and be serialized to `null`. - - #### Storage - - Floating-point number values are stored directly inside a @ref basic_json - type. - - @sa @ref number_integer_t -- type for number values (integer) - - @sa @ref number_unsigned_t -- type for number values (unsigned integer) - - @since version 1.0.0 - */ - using number_float_t = NumberFloatType; - - /// @} - - private: - - /// helper for exception-safe object creation - template - static T* create(Args&& ... args) - { - AllocatorType alloc; - using AllocatorTraits = std::allocator_traits>; - - auto deleter = [&](T * object) - { - AllocatorTraits::deallocate(alloc, object, 1); - }; - std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); - AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); - assert(object != nullptr); - return object.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create(); - break; - } - - case value_t::array: - { - array = create(); - break; - } - - case value_t::string: - { - string = create(""); - break; - } - - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } - - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } - - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } - - case value_t::null: - { - object = nullptr; // silence warning, see #821 - break; - } - - default: - { - object = nullptr; // silence warning, see #821 - if (JSON_UNLIKELY(t == value_t::null)) - { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) - { - string = create(value); - } - - /// constructor for rvalue strings - json_value(string_t&& value) - { - string = create(std::move(value)); - } - - /// constructor for objects - json_value(const object_t& value) - { - object = create(value); - } - - /// constructor for rvalue objects - json_value(object_t&& value) - { - object = create(std::move(value)); - } - - /// constructor for arrays - json_value(const array_t& value) - { - array = create(value); - } - - /// constructor for rvalue arrays - json_value(array_t&& value) - { - array = create(std::move(value)); - } - - void destroy(value_t t) noexcept - { - switch (t) - { - case value_t::object: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, object); - std::allocator_traits::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, array); - std::allocator_traits::deallocate(alloc, array, 1); - break; - } - - case value_t::string: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, string); - std::allocator_traits::deallocate(alloc, string, 1); - break; - } - - default: - { - break; - } - } - } - }; - - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - */ - void assert_invariant() const noexcept - { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /*! - @brief parser event types - - The parser callback distinguishes the following events: - - `object_start`: the parser read `{` and started to process a JSON object - - `key`: the parser read a key of a value in an object - - `object_end`: the parser read `}` and finished processing a JSON object - - `array_start`: the parser read `[` and started to process a JSON array - - `array_end`: the parser read `]` and finished processing a JSON array - - `value`: the parser finished reading a JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - @sa @ref parser_callback_t for more information and examples - */ - using parse_event_t = typename parser::parse_event_t; - - /*! - @brief per-element parser callback type - - With a parser callback function, the result of parsing a JSON text can be - influenced. When passed to @ref parse, it is called on certain events - (passed as @ref parse_event_t via parameter @a event) with a set recursion - depth @a depth and context JSON value @a parsed. The return value of the - callback function is a boolean indicating whether the element that emitted - the callback shall be kept or not. - - We distinguish six scenarios (determined by the event type) in which the - callback function can be called. The following table describes the values - of the parameters @a depth, @a event, and @a parsed. - - parameter @a event | description | parameter @a depth | parameter @a parsed - ------------------ | ----------- | ------------------ | ------------------- - parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded - parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key - parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object - parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded - parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array - parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - - @image html callback_events.png "Example when certain parse events are triggered" - - Discarding a value (i.e., returning `false`) has different effects - depending on the context in which function was called: - - - Discarded values in structured types are skipped. That is, the parser - will behave as if the discarded value was never read. - - In case a value outside a structured type is skipped, it is replaced - with `null`. This case happens if the top-level element is skipped. - - @param[in] depth the depth of the recursion during parsing - - @param[in] event an event of type parse_event_t indicating the context in - the callback function has been called - - @param[in,out] parsed the current intermediate parse result; note that - writing to this value has no effect for parse_event_t::key events - - @return Whether the JSON value which called the function during parsing - should be kept (`true`) or not (`false`). In the latter case, it is either - skipped completely or replaced by an empty discarded object. - - @sa @ref parse for examples - - @since version 1.0.0 - */ - using parser_callback_t = typename parser::parser_callback_t; - - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /*! - @brief create an empty value with a given type - - Create an empty JSON value with a given type. The value will be default - initialized with an empty value which depends on the type: - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @param[in] v the type of the value to create - - @complexity Constant. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows the constructor for different @ref - value_t values,basic_json__value_t} - - @sa @ref clear() -- restores the postcondition of this constructor - - @since version 1.0.0 - */ - basic_json(const value_t v) - : m_type(v), m_value(v) - { - assert_invariant(); - } - - /*! - @brief create a null object - - Create a `null` JSON value. It either takes a null pointer as parameter - (explicitly creating `null`) or no parameter (implicitly creating `null`). - The passed null pointer itself is not read -- it is only used to choose - the right constructor. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @liveexample{The following code shows the constructor with and without a - null pointer parameter.,basic_json__nullptr_t} - - @since version 1.0.0 - */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } - - /*! - @brief create a JSON value - - This is a "catch all" constructor for all compatible JSON types; that is, - types for which a `to_json()` method exists. The constructor forwards the - parameter @a val to that method (to `json_serializer::to_json` method - with `U = uncvref_t`, to be exact). - - Template type @a CompatibleType includes, but is not limited to, the - following types: - - **arrays**: @ref array_t and all kinds of compatible containers such as - `std::vector`, `std::deque`, `std::list`, `std::forward_list`, - `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, - `std::multiset`, and `std::unordered_multiset` with a `value_type` from - which a @ref basic_json value can be constructed. - - **objects**: @ref object_t and all kinds of compatible associative - containers such as `std::map`, `std::unordered_map`, `std::multimap`, - and `std::unordered_multimap` with a `key_type` compatible to - @ref string_t and a `value_type` from which a @ref basic_json value can - be constructed. - - **strings**: @ref string_t, string literals, and all compatible string - containers can be used. - - **numbers**: @ref number_integer_t, @ref number_unsigned_t, - @ref number_float_t, and all convertible number types such as `int`, - `size_t`, `int64_t`, `float` or `double` can be used. - - **boolean**: @ref boolean_t / `bool` can be used. - - See the examples below. - - @tparam CompatibleType a type such that: - - @a CompatibleType is not derived from `std::istream`, - - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move - constructors), - - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) - - @a CompatibleType is not a @ref basic_json nested type (e.g., - @ref json_pointer, @ref iterator, etc ...) - - @ref @ref json_serializer has a - `to_json(basic_json_t&, CompatibleType&&)` method - - @tparam U = `uncvref_t` - - @param[in] val the value to be forwarded to the respective constructor - - @complexity Usually linear in the size of the passed @a val, also - depending on the implementation of the called `to_json()` - method. - - @exceptionsafety Depends on the called constructor. For types directly - supported by the library (i.e., all types for which no `to_json()` function - was provided), strong guarantee holds: if an exception is thrown, there are - no changes to any JSON value. - - @liveexample{The following code shows the constructor with several - compatible types.,basic_json__CompatibleType} - - @since version 2.1.0 - */ - template , - detail::enable_if_t< - detail::is_compatible_type::value, int> = 0> - basic_json(CompatibleType && val) noexcept(noexcept( - JSONSerializer::to_json(std::declval(), - std::forward(val)))) - { - JSONSerializer::to_json(*this, std::forward(val)); - assert_invariant(); - } - - /*! - @brief create a JSON value from an existing one - - This is a constructor for existing @ref basic_json types. - It does not hijack copy/move constructors, since the parameter has different - template arguments than the current ones. - - The constructor tries to convert the internal @ref m_value of the parameter. - - @tparam BasicJsonType a type such that: - - @a BasicJsonType is a @ref basic_json type. - - @a BasicJsonType has different template arguments than @ref basic_json_t. - - @param[in] val the @ref basic_json value to be converted. - - @complexity Usually linear in the size of the passed @a val, also - depending on the implementation of the called `to_json()` - method. - - @exceptionsafety Depends on the called constructor. For types directly - supported by the library (i.e., all types for which no `to_json()` function - was provided), strong guarantee holds: if an exception is thrown, there are - no changes to any JSON value. - - @since version 3.1.2 - */ - template ::value and not std::is_same::value, int> = 0> - basic_json(const BasicJsonType& val) - { - using other_boolean_t = typename BasicJsonType::boolean_t; - using other_number_float_t = typename BasicJsonType::number_float_t; - using other_number_integer_t = typename BasicJsonType::number_integer_t; - using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using other_string_t = typename BasicJsonType::string_t; - using other_object_t = typename BasicJsonType::object_t; - using other_array_t = typename BasicJsonType::array_t; - - switch (val.type()) - { - case value_t::boolean: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_float: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_integer: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_unsigned: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::string: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::object: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::array: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::null: - *this = nullptr; - break; - case value_t::discarded: - m_type = value_t::discarded; - break; - } - assert_invariant(); - } - - /*! - @brief create a container (array or object) from an initializer list - - Creates a JSON value of type array or object from the passed initializer - list @a init. In case @a type_deduction is `true` (default), the type of - the JSON value to be created is deducted from the initializer list @a init - according to the following rules: - - 1. If the list is empty, an empty JSON object value `{}` is created. - 2. If the list consists of pairs whose first element is a string, a JSON - object value is created where the first elements of the pairs are - treated as keys and the second elements are as values. - 3. In all other cases, an array is created. - - The rules aim to create the best fit between a C++ initializer list and - JSON values. The rationale is as follows: - - 1. The empty initializer list is written as `{}` which is exactly an empty - JSON object. - 2. C++ has no way of describing mapped types other than to list a list of - pairs. As JSON requires that keys must be of type string, rule 2 is the - weakest constraint one can pose on initializer lists to interpret them - as an object. - 3. In all other cases, the initializer list could not be interpreted as - JSON object type, so interpreting it as JSON array type is safe. - - With the rules described above, the following JSON values cannot be - expressed by an initializer list: - - - the empty array (`[]`): use @ref array(initializer_list_t) - with an empty initializer list in this case - - arrays whose elements satisfy rule 2: use @ref - array(initializer_list_t) with the same initializer list - in this case - - @note When used without parentheses around an empty initializer list, @ref - basic_json() is called instead of this function, yielding the JSON null - value. - - @param[in] init initializer list with JSON values - - @param[in] type_deduction internal parameter; when set to `true`, the type - of the JSON value is deducted from the initializer list @a init; when set - to `false`, the type provided via @a manual_type is forced. This mode is - used by the functions @ref array(initializer_list_t) and - @ref object(initializer_list_t). - - @param[in] manual_type internal parameter; when @a type_deduction is set - to `false`, the created JSON value will use the provided type (only @ref - value_t::array and @ref value_t::object are valid); when @a type_deduction - is set to `true`, this parameter has no effect - - @throw type_error.301 if @a type_deduction is `false`, @a manual_type is - `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string. In this case, the constructor could not - create an object. If @a type_deduction would have be `true`, an array - would have been created. See @ref object(initializer_list_t) - for an example. - - @complexity Linear in the size of the initializer list @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The example below shows how JSON values are created from - initializer lists.,basic_json__list_init_t} - - @sa @ref array(initializer_list_t) -- create a JSON array - value from an initializer list - @sa @ref object(initializer_list_t) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - basic_json(initializer_list_t init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const detail::json_ref& element_ref) - { - return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); - }); - - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) - { - JSON_THROW(type_error::create(301, "cannot create object from initializer list")); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - - std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) - { - auto element = element_ref.moved_or_copied(); - m_value.object->emplace( - std::move(*((*element.m_value.array)[0].m_value.string)), - std::move((*element.m_value.array)[1])); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init.begin(), init.end()); - } - - assert_invariant(); - } - - /*! - @brief explicitly create an array from an initializer list - - Creates a JSON array value from a given initializer list. That is, given a - list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the - initializer list is empty, the empty array `[]` is created. - - @note This function is only needed to express two edge cases that cannot - be realized with the initializer list constructor (@ref - basic_json(initializer_list_t, bool, value_t)). These cases - are: - 1. creating an array whose elements are all pairs whose first element is a - string -- in this case, the initializer list constructor would create an - object, taking the first elements as keys - 2. creating an empty array -- passing the empty initializer list to the - initializer list constructor yields an empty object - - @param[in] init initializer list with JSON values to create an array from - (optional) - - @return JSON array value - - @complexity Linear in the size of @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows an example for the `array` - function.,array} - - @sa @ref basic_json(initializer_list_t, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref object(initializer_list_t) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - static basic_json array(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::array); - } - - /*! - @brief explicitly create an object from an initializer list - - Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elements must be strings. If - the initializer list is empty, the empty object `{}` is created. - - @note This function is only added for symmetry reasons. In contrast to the - related function @ref array(initializer_list_t), there are - no cases which can only be expressed by this function. That is, any - initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(initializer_list_t, bool, value_t). - - @param[in] init initializer list to create an object from (optional) - - @return JSON object value - - @throw type_error.301 if @a init is not a list of pairs whose first - elements are strings. In this case, no object can be created. When such a - value is passed to @ref basic_json(initializer_list_t, bool, value_t), - an array would have been created from the passed initializer list @a init. - See example below. - - @complexity Linear in the size of @a init. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows an example for the `object` - function.,object} - - @sa @ref basic_json(initializer_list_t, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref array(initializer_list_t) -- create a JSON array - value from an initializer list - - @since version 1.0.0 - */ - static basic_json object(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::object); - } - - /*! - @brief construct an array with count copies of given value - - Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. - - @param[in] cnt the number of JSON copies of @a val to create - @param[in] val the JSON value to copy - - @post `std::distance(begin(),end()) == cnt` holds. - - @complexity Linear in @a cnt. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The following code shows examples for the @ref - basic_json(size_type\, const basic_json&) - constructor.,basic_json__size_type_basic_json} - - @since version 1.0.0 - */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create(cnt, val); - assert_invariant(); - } - - /*! - @brief construct a JSON container given an iterator range - - Constructs the JSON value with the contents of the range `[first, last)`. - The semantics depends on the different types a JSON value can have: - - In case of a null type, invalid_iterator.206 is thrown. - - In case of other primitive types (number, boolean, or string), @a first - must be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, invalid_iterator.204 is thrown. - - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector` or `std::map`; that is, a JSON array - or object is constructed from the values in the range. - - @tparam InputIT an input iterator type (@ref iterator or @ref - const_iterator) - - @param[in] first begin of the range to copy from (included) - @param[in] last end of the range to copy from (excluded) - - @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion (see warning).** If - assertions are switched off, a violation of this precondition yields - undefined behavior. - - @pre Range `[first, last)` is valid. Usually, this precondition cannot be - checked efficiently. Only certain edge cases are detected; see the - description of the exceptions below. A violation of this precondition - yields undefined behavior. - - @warning A precondition is enforced with a runtime assertion that will - result in calling `std::abort` if this precondition is not met. - Assertions can be disabled by defining `NDEBUG` at compile time. - See http://en.cppreference.com/w/cpp/error/assert for more - information. - - @throw invalid_iterator.201 if iterators @a first and @a last are not - compatible (i.e., do not belong to the same JSON value). In this case, - the range `[first, last)` is undefined. - @throw invalid_iterator.204 if iterators @a first and @a last belong to a - primitive type (number, boolean, or string), but @a first does not point - to the first element any more. In this case, the range `[first, last)` is - undefined. See example code below. - @throw invalid_iterator.206 if iterators @a first and @a last belong to a - null value. In this case, the range `[first, last)` is undefined. - - @complexity Linear in distance between @a first and @a last. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @liveexample{The example below shows several ways to create JSON values by - specifying a subrange with iterators.,basic_json__InputIt_InputIt} - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type = 0> - basic_json(InputIT first, InputIT last) - { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); - - // make sure iterator fits the current value - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); - } - - // copy type from first iterator - m_type = first.m_object->m_type; - - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() - or not last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } - break; - } - - default: - break; - } - - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } - - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } - - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } - - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + - std::string(first.m_object->type_name()))); - } - - assert_invariant(); - } - - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - /// @private - basic_json(const detail::json_ref& ref) - : basic_json(ref.moved_or_copied()) - {} - - /*! - @brief copy constructor - - Creates a copy of a given JSON value. - - @param[in] other the JSON value to copy - - @post `*this == other` - - @complexity Linear in the size of @a other. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes to any JSON value. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - As postcondition, it holds: `other == basic_json(other)`. - - @liveexample{The following code shows an example for the copy - constructor.,basic_json__basic_json} - - @since version 1.0.0 - */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } - - case value_t::array: - { - m_value = *other.m_value.array; - break; - } - - case value_t::string: - { - m_value = *other.m_value.string; - break; - } - - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } - - default: - break; - } - - assert_invariant(); - } - - /*! - @brief move constructor - - Move constructor. Constructs a JSON value with the contents of the given - value @a other using move semantics. It "steals" the resources from @a - other and leaves it as JSON null value. - - @param[in,out] other value to move to this object - - @post `*this` has the same value as @a other before the call. - @post @a other is a JSON null value. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @requirement This function helps `basic_json` satisfying the - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) - requirements. - - @liveexample{The code below shows the move constructor explicitly called - via std::move.,basic_json__moveconstructor} - - @since version 1.0.0 - */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); - - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; - - assert_invariant(); - } - - /*! - @brief copy assignment - - Copy assignment operator. Copies a JSON value via the "copy and swap" - strategy: It is expressed in terms of the copy constructor, destructor, - and the `swap()` member function. - - @param[in] other value to copy from - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - @liveexample{The code below shows and example for the copy assignment. It - creates a copy of value `a` which is then swapped with `b`. Finally\, the - copy of `a` (which is the null value after the swap) is - destroyed.,basic_json__copyassignment} - - @since version 1.0.0 - */ - reference& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); - - assert_invariant(); - return *this; - } - - /*! - @brief destructor - - Destroys the JSON value and frees all allocated memory. - - @complexity Linear. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - All stored elements are destroyed and all memory is freed. - - @since version 1.0.0 - */ - ~basic_json() noexcept - { - assert_invariant(); - m_value.destroy(m_type); - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /*! - @brief serialization - - Serialization function for JSON values. The function tries to mimic - Python's `json.dumps()` function, and currently supports its @a indent - and @a ensure_ascii parameters. - - @param[in] indent If indent is nonnegative, then array elements and object - members will be pretty-printed with that indent level. An indent level of - `0` will only insert newlines. `-1` (the default) selects the most compact - representation. - @param[in] indent_char The character to use for indentation if @a indent is - greater than `0`. The default is ` ` (space). - @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters - in the output are escaped with `\uXXXX` sequences, and the result consists - of ASCII characters only. - - @return string containing the serialization of the JSON value - - @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded - - @complexity Linear. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @liveexample{The following example shows the effect of different @a indent\, - @a indent_char\, and @a ensure_ascii parameters to the result of the - serialization.,dump} - - @see https://docs.python.org/2/library/json.html#json.dump - - @since version 1.0.0; indentation character @a indent_char, option - @a ensure_ascii and exceptions added in version 3.0.0 - */ - string_t dump(const int indent = -1, const char indent_char = ' ', - const bool ensure_ascii = false) const - { - string_t result; - serializer s(detail::output_adapter(result), indent_char); - - if (indent >= 0) - { - s.dump(*this, true, ensure_ascii, static_cast(indent)); - } - else - { - s.dump(*this, false, ensure_ascii, 0); - } - - return result; - } - - /*! - @brief return the type of the JSON value (explicit) - - Return the type of the JSON value as a value from the @ref value_t - enumeration. - - @return the type of the JSON value - Value type | return value - ------------------------- | ------------------------- - null | value_t::null - boolean | value_t::boolean - string | value_t::string - number (integer) | value_t::number_integer - number (unsigned integer) | value_t::number_unsigned - number (floating-point) | value_t::number_float - object | value_t::object - array | value_t::array - discarded | value_t::discarded - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `type()` for all JSON - types.,type} - - @sa @ref operator value_t() -- return the type of the JSON value (implicit) - @sa @ref type_name() -- return the type as string - - @since version 1.0.0 - */ - constexpr value_t type() const noexcept - { - return m_type; - } - - /*! - @brief return whether type is primitive - - This function returns true if and only if the JSON type is primitive - (string, number, boolean, or null). - - @return `true` if type is primitive (string, number, boolean, or null), - `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_primitive()` for all JSON - types.,is_primitive} - - @sa @ref is_structured() -- returns whether JSON value is structured - @sa @ref is_null() -- returns whether JSON value is `null` - @sa @ref is_string() -- returns whether JSON value is a string - @sa @ref is_boolean() -- returns whether JSON value is a boolean - @sa @ref is_number() -- returns whether JSON value is a number - - @since version 1.0.0 - */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } - - /*! - @brief return whether type is structured - - This function returns true if and only if the JSON type is structured - (array or object). - - @return `true` if type is structured (array or object), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_structured()` for all JSON - types.,is_structured} - - @sa @ref is_primitive() -- returns whether value is primitive - @sa @ref is_array() -- returns whether value is an array - @sa @ref is_object() -- returns whether value is an object - - @since version 1.0.0 - */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } - - /*! - @brief return whether value is null - - This function returns true if and only if the JSON value is null. - - @return `true` if type is null, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_null()` for all JSON - types.,is_null} - - @since version 1.0.0 - */ - constexpr bool is_null() const noexcept - { - return (m_type == value_t::null); - } - - /*! - @brief return whether value is a boolean - - This function returns true if and only if the JSON value is a boolean. - - @return `true` if type is boolean, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_boolean()` for all JSON - types.,is_boolean} - - @since version 1.0.0 - */ - constexpr bool is_boolean() const noexcept - { - return (m_type == value_t::boolean); - } - - /*! - @brief return whether value is a number - - This function returns true if and only if the JSON value is a number. This - includes both integer (signed and unsigned) and floating-point values. - - @return `true` if type is number (regardless whether integer, unsigned - integer or floating-type), `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number()` for all JSON - types.,is_number} - - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number() const noexcept - { - return is_number_integer() or is_number_float(); - } - - /*! - @brief return whether value is an integer number - - This function returns true if and only if the JSON value is a signed or - unsigned integer number. This excludes floating-point values. - - @return `true` if type is an integer or unsigned integer number, `false` - otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_integer()` for all - JSON types.,is_number_integer} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 1.0.0 - */ - constexpr bool is_number_integer() const noexcept - { - return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); - } - - /*! - @brief return whether value is an unsigned integer number - - This function returns true if and only if the JSON value is an unsigned - integer number. This excludes floating-point and signed integer values. - - @return `true` if type is an unsigned integer number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_unsigned()` for all - JSON types.,is_number_unsigned} - - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_float() -- check if value is a floating-point number - - @since version 2.0.0 - */ - constexpr bool is_number_unsigned() const noexcept - { - return (m_type == value_t::number_unsigned); - } - - /*! - @brief return whether value is a floating-point number - - This function returns true if and only if the JSON value is a - floating-point number. This excludes signed and unsigned integer values. - - @return `true` if type is a floating-point number, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_number_float()` for all - JSON types.,is_number_float} - - @sa @ref is_number() -- check if value is number - @sa @ref is_number_integer() -- check if value is an integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - - @since version 1.0.0 - */ - constexpr bool is_number_float() const noexcept - { - return (m_type == value_t::number_float); - } - - /*! - @brief return whether value is an object - - This function returns true if and only if the JSON value is an object. - - @return `true` if type is object, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_object()` for all JSON - types.,is_object} - - @since version 1.0.0 - */ - constexpr bool is_object() const noexcept - { - return (m_type == value_t::object); - } - - /*! - @brief return whether value is an array - - This function returns true if and only if the JSON value is an array. - - @return `true` if type is array, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_array()` for all JSON - types.,is_array} - - @since version 1.0.0 - */ - constexpr bool is_array() const noexcept - { - return (m_type == value_t::array); - } - - /*! - @brief return whether value is a string - - This function returns true if and only if the JSON value is a string. - - @return `true` if type is string, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_string()` for all JSON - types.,is_string} - - @since version 1.0.0 - */ - constexpr bool is_string() const noexcept - { - return (m_type == value_t::string); - } - - /*! - @brief return whether value is discarded - - This function returns true if and only if the JSON value was discarded - during parsing with a callback function (see @ref parser_callback_t). - - @note This function will always be `false` for JSON values after parsing. - That is, discarded values can only occur during parsing, but will be - removed when inside a structured value or replaced by null in other cases. - - @return `true` if type is discarded, `false` otherwise. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies `is_discarded()` for all JSON - types.,is_discarded} - - @since version 1.0.0 - */ - constexpr bool is_discarded() const noexcept - { - return (m_type == value_t::discarded); - } - - /*! - @brief return the type of the JSON value (implicit) - - Implicitly return the type of the JSON value as a value from the @ref - value_t enumeration. - - @return the type of the JSON value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @liveexample{The following code exemplifies the @ref value_t operator for - all JSON types.,operator__value_t} - - @sa @ref type() -- return the type of the JSON value (explicit) - @sa @ref type_name() -- return the type as string - - @since version 1.0.0 - */ - constexpr operator value_t() const noexcept - { - return m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (JSON_LIKELY(is_boolean())) - { - return m_value.boolean; - } - - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This function helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw type_error.303 if ReferenceType does not match underlying value - type of the current JSON - */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr::type>(); - - if (JSON_LIKELY(ptr != nullptr)) - { - return *ptr; - } - - JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); - } - - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get special-case overload - - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this - - @complexity Constant. - - @since version 2.1.0 - */ - template::type, basic_json_t>::value, - int> = 0> - basic_json get() const - { - return *this; - } - - /*! - @brief get special-case overload - - This overloads converts the current @ref basic_json in a different - @ref basic_json type - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this, converted into @tparam BasicJsonType - - @complexity Depending on the implementation of the called `from_json()` - method. - - @since version 3.1.2 - */ - template::value and - detail::is_basic_json::value, int> = 0> - BasicJsonType get() const - { - return *this; - } - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer has a `from_json()` method of the form - `void from_json(const basic_json&, ValueType&)`, and - - @ref json_serializer does not have a `from_json()` method of - the form `ValueType from_json(const basic_json&)` - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @since version 2.1.0 - */ - template, - detail::enable_if_t < - not detail::is_basic_json::value and - detail::has_from_json::value and - not detail::has_non_default_from_json::value, - int> = 0> - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get(), which is why we - // still need the uncvref - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - static_assert(std::is_default_constructible::value, - "types must be DefaultConstructible when used with get()"); - - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - } - - /*! - @brief get a value (explicit); special case - - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - return JSONSerializer::from_json(*this); - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer has a `from_json()` method of the form - `ValueType from_json(const basic_json&)` - - @note If @ref json_serializer has both overloads of - `from_json()`, this one is chosen. - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @since version 2.1.0 - */ - template, - detail::enable_if_t::value and - detail::has_non_default_from_json::value, - int> = 0> - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) - { - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return JSONSerializer::from_json(*this); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } - - /*! - @brief get a pointer value (implicit) - - Implicit pointer access to the internally stored JSON value. No copies are - made. - - @warning Writing data to the pointee of the result yields an undefined - state. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} - - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } - - /*! - @brief get a reference value (implicit) - - Implicit reference access to the internally stored JSON value. No copies - are made. - - @warning Writing data to the referee of the result yields an undefined - state. - - @tparam ReferenceType reference type; must be a reference to @ref array_t, - @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or - @ref number_float_t. Enforced by static assertion. - - @return reference to the internally stored JSON value if the requested - reference type @a ReferenceType fits to the JSON value; throws - type_error.303 otherwise - - @throw type_error.303 in case passed type @a ReferenceType is incompatible - with the stored JSON value; see example below - - @complexity Constant. - - @liveexample{The example shows several calls to `get_ref()`.,get_ref} - - @since version 1.1.0 - */ - template::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a reference value (implicit) - @copydoc get_ref() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw type_error.302 in case passed type @a ValueType is incompatible - to the JSON value type (e.g., the JSON value is of type boolean, but a - string is requested); see example below - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer::value and - not std::is_same>::value and - not std::is_same::value and - not detail::is_basic_json::value -#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 - and not std::is_same>::value -#endif -#if defined(JSON_HAS_CPP_17) - and not std::is_same::value -#endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } - - /// @} - - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /*! - @brief access specified array element with bounds checking - - Returns a reference to the element at specified location @a idx, with - bounds checking. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 1.0.0 - - @liveexample{The example below shows how array elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__size_type} - */ - reference at(size_type idx) - { - // at only works for arrays - if (JSON_LIKELY(is_array())) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified array element with bounds checking - - Returns a const reference to the element at specified location @a idx, - with bounds checking. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 1.0.0 - - @liveexample{The example below shows how array elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__size_type_const} - */ - const_reference at(size_type idx) const - { - // at only works for arrays - if (JSON_LIKELY(is_array())) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a reference to the element at with specified key @a key, with - bounds checking. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Logarithmic in the size of the container. - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - - @liveexample{The example below shows how object elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__object_t_key_type} - */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified object element with bounds checking - - Returns a const reference to the element at with specified key @a key, - with bounds checking. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Logarithmic in the size of the container. - - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - - @liveexample{The example below shows how object elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__object_t_key_type_const} - */ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); - } - } - - /*! - @brief access specified array element - - Returns a reference to the element at specified location @a idx. - - @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), - then the array is silently filled up with `null` values to make `idx` a - valid reference to the last stored element. - - @param[in] idx index of the element to access - - @return reference to the element at index @a idx - - @throw type_error.305 if the JSON value is not an array or null; in that - cases, using the [] operator with an index makes no sense. - - @complexity Constant if @a idx is in the range of the array. Otherwise - linear in `idx - size()`. - - @liveexample{The example below shows how array elements can be read and - written using `[]` operator. Note the addition of `null` - values.,operatorarray__size_type} - - @since version 1.0.0 - */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } - - // operator[] only works for arrays - if (JSON_LIKELY(is_array())) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); - } - - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified array element - - Returns a const reference to the element at specified location @a idx. - - @param[in] idx index of the element to access - - @return const reference to the element at index @a idx - - @throw type_error.305 if the JSON value is not an array; in that case, - using the [] operator with an index makes no sense. - - @complexity Constant. - - @liveexample{The example below shows how array elements can be read using - the `[]` operator.,operatorarray__size_type_const} - - @since version 1.0.0 - */ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (JSON_LIKELY(is_array())) - { - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - // operator[] only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->operator[](key); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw type_error.305 if the JSON value is not an object; in that case, - using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.0.0 - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (JSON_LIKELY(is_object())) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->operator[](key); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief read-only access specified object element - - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. - - @warning If the element with key @a key does not exist, the behavior is - undefined. - - @param[in] key key of the element to access - - @return const reference to the element at key @a key - - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** - - @throw type_error.305 if the JSON value is not an object; in that case, - using the [] operator with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value - - @since version 1.1.0 - */ - template - const_reference operator[](T* key) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); - } - - /*! - @brief access specified object element with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(key); - } catch(out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const typename object_t::key_type&), this function - does not throw if the given key @a key was not found. - - @note Unlike @ref operator[](const typename object_t::key_type& key), this - function does not implicitly add an element to the position defined by @a - key. This function is furthermore also applicable to const objects. - - @param[in] key key of the element to access - @param[in] default_value the value to return if @a key is not found - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw type_error.306 if the JSON value is not an object; in that case, - using `value()` with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value} - - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - - @since version 1.0.0 - */ - template::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return *it; - } - - return default_value; - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const - */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } - - /*! - @brief access specified object element via JSON Pointer with default value - - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. - - The function is basically equivalent to executing - @code {.cpp} - try { - return at(ptr); - } catch(out_of_range) { - return default_value; - } - @endcode - - @note Unlike @ref at(const json_pointer&), this function does not throw - if the given key @a key was not found. - - @param[in] ptr a JSON pointer to the element to access - @param[in] default_value the value to return if @a ptr found no value - - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. - - @return copy of the element at key @a key or @a default_value if @a key - is not found - - @throw type_error.306 if the JSON value is not an objec; in that case, - using `value()` with a key makes no sense. - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value_ptr} - - @sa @ref operator[](const json_pointer&) for unchecked access by reference - - @since version 2.0.2 - */ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, const ValueType& default_value) const - { - // at only works for objects - if (JSON_LIKELY(is_object())) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this); - } - JSON_CATCH (out_of_range&) - { - return default_value; - } - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); - } - - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const json_pointer&, ValueType) const - */ - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } - - /*! - @brief access the first element - - Returns a reference to the first element in the container. For a JSON - container `c`, the expression `c.front()` is equivalent to `*c.begin()`. - - @return In case of a structured type (array or object), a reference to the - first element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw invalid_iterator.214 when called on `null` value - - @liveexample{The following code shows an example for `front()`.,front} - - @sa @ref back() -- access the last element - - @since version 1.0.0 - */ - reference front() - { - return *begin(); - } - - /*! - @copydoc basic_json::front() - */ - const_reference front() const - { - return *cbegin(); - } - - /*! - @brief access the last element - - Returns a reference to the last element in the container. For a JSON - container `c`, the expression `c.back()` is equivalent to - @code {.cpp} - auto tmp = c.end(); - --tmp; - return *tmp; - @endcode - - @return In case of a structured type (array or object), a reference to the - last element is returned. In case of number, string, or boolean values, a - reference to the value is returned. - - @complexity Constant. - - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. - - @throw invalid_iterator.214 when called on a `null` value. See example - below. - - @liveexample{The following code shows an example for `back()`.,back} - - @sa @ref front() -- access the first element - - @since version 1.0.0 - */ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /*! - @copydoc basic_json::back() - */ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /*! - @brief remove element given an iterator - - Removes the element specified by iterator @a pos. The iterator @a pos must - be valid and dereferenceable. Thus the `end()` iterator (which is valid, - but is not dereferenceable) cannot be used as a value for @a pos. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] pos iterator to the element to remove - @return Iterator following the last removed element. If the iterator @a - pos refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.202 if called on an iterator which does not belong - to the current JSON value; example: `"iterator does not fit current - value"` - @throw invalid_iterator.205 if called on a primitive type with invalid - iterator (i.e., any iterator which is not `begin()`); example: `"iterator - out of range"` - - @complexity The complexity depends on the type: - - objects: amortized constant - - arrays: linear in distance between @a pos and the end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType} - - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (JSON_UNLIKELY(this != pos.m_object)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) - { - JSON_THROW(invalid_iterator::create(205, "iterator out of range")); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } - - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - return result; - } - - /*! - @brief remove elements given an iterator range - - Removes the element specified by the range `[first; last)`. The iterator - @a first does not need to be dereferenceable if `first == last`: erasing - an empty range is a no-op. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] first iterator to the beginning of the range to remove - @param[in] last iterator past the end of the range to remove - @return Iterator following the last removed element. If the iterator @a - second refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.203 if called on iterators which does not belong - to the current JSON value; example: `"iterators do not fit current value"` - @throw invalid_iterator.204 if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`); example: - `"iterators out of range"` - - @complexity The complexity depends on the type: - - objects: `log(size()) + std::distance(first, last)` - - arrays: linear in the distance between @a first and @a last, plus linear - in the distance between @a last and end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType_IteratorType} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) - { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() - or not last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - return result; - } - - /*! - @brief remove element from a JSON object given a key - - Removes elements from a JSON object with the key value @a key. - - @param[in] key value of the elements to remove - - @return Number of elements removed. If @a ObjectType is the default - `std::map` type, the return value will always be `0` (@a key was not - found) or `1` (@a key was found). - - @post References and iterators to the erased elements are invalidated. - Other references and iterators are not affected. - - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` - - @complexity `log(size()) + count(key)` - - @liveexample{The example shows the effect of `erase()`.,erase__key_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (JSON_LIKELY(is_object())) - { - return m_value.object->erase(key); - } - - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - - /*! - @brief remove element from a JSON array given an index - - Removes element from a JSON array at the index @a idx. - - @param[in] idx index of the element to remove - - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` - @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 - is out of range"` - - @complexity Linear in distance between @a idx and the end of the container. - - @liveexample{The example shows the effect of `erase()`.,erase__size_type} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - - @since version 1.0.0 - */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (JSON_LIKELY(is_array())) - { - if (JSON_UNLIKELY(idx >= size())) - { - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); - } - } - - /// @} - - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /*! - @brief find an element in a JSON object - - Finds an element in a JSON object with key equivalent to @a key. If the - element is not found or the JSON value is not an object, end() is - returned. - - @note This method always returns @ref end() when executed on a JSON type - that is not an object. - - @param[in] key key value of the element to search for. - - @return Iterator to an element with key equivalent to @a key. If no such - element is found or the JSON value is not an object, past-the-end (see - @ref end()) iterator is returned. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `find()` is used.,find__key_type} - - @since version 1.0.0 - */ - template - iterator find(KeyT&& key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /*! - @brief find an element in a JSON object - @copydoc find(KeyT&&) - */ - template - const_iterator find(KeyT&& key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /*! - @brief returns the number of occurrences of a key in a JSON object - - Returns the number of elements with key @a key. If ObjectType is the - default `std::map` type, the return value will always be `0` (@a key was - not found) or `1` (@a key was found). - - @note This method always returns `0` when executed on a JSON type that is - not an object. - - @param[in] key key value of the element to count - - @return Number of elements with key @a key. If the JSON value is not an - object, the return value will be `0`. - - @complexity Logarithmic in the size of the JSON object. - - @liveexample{The example shows how `count()` is used.,count} - - @since version 1.0.0 - */ - template - size_type count(KeyT&& key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(std::forward(key)) : 0; - } - - /// @} - - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /*! - @brief returns an iterator to the first element - - Returns an iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `begin()`.,begin} - - @sa @ref cbegin() -- returns a const iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /*! - @copydoc basic_json::cbegin() - */ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /*! - @brief returns a const iterator to the first element - - Returns a const iterator to the first element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator to the first element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).begin()`. - - @liveexample{The following code shows an example for `cbegin()`.,cbegin} - - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end - - @since version 1.0.0 - */ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /*! - @brief returns an iterator to one past the last element - - Returns an iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - @liveexample{The following code shows an example for `end()`.,end} - - @sa @ref cend() -- returns a const iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /*! - @copydoc basic_json::cend() - */ - const_iterator end() const noexcept - { - return cend(); - } - - /*! - @brief returns a const iterator to one past the last element - - Returns a const iterator to one past the last element. - - @image html range-begin-end.svg "Illustration from cppreference.com" - - @return const iterator one past the last element - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).end()`. - - @liveexample{The following code shows an example for `cend()`.,cend} - - @sa @ref end() -- returns an iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning - - @since version 1.0.0 - */ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /*! - @brief returns an iterator to the reverse-beginning - - Returns an iterator to the reverse-beginning; that is, the last element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(end())`. - - @liveexample{The following code shows an example for `rbegin()`.,rbegin} - - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /*! - @copydoc basic_json::crbegin() - */ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /*! - @brief returns an iterator to the reverse-end - - Returns an iterator to the reverse-end; that is, one before the first - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(begin())`. - - @liveexample{The following code shows an example for `rend()`.,rend} - - @sa @ref crend() -- returns a const reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /*! - @copydoc basic_json::crend() - */ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /*! - @brief returns a const reverse iterator to the last element - - Returns a const iterator to the reverse-beginning; that is, the last - element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rbegin()`. - - @liveexample{The following code shows an example for `crbegin()`.,crbegin} - - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end - - @since version 1.0.0 - */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /*! - @brief returns a const reverse iterator to one before the first - - Returns a const reverse iterator to the reverse-end; that is, one before - the first element. - - @image html range-rbegin-rend.svg "Illustration from cppreference.com" - - @complexity Constant. - - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rend()`. - - @liveexample{The following code shows an example for `crend()`.,crend} - - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - - @since version 1.0.0 - */ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. - - For loop without iterator_wrapper: - - @code{cpp} - for (auto it = j_object.begin(); it != j_object.end(); ++it) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - Range-based for loop without iterator proxy: - - @code{cpp} - for (auto it : j_object) - { - // "it" is of type json::reference and has no key() member - std::cout << "value: " << it << '\n'; - } - @endcode - - Range-based for loop with iterator proxy: - - @code{cpp} - for (auto it : json::iterator_wrapper(j_object)) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - @note When iterating over an array, `key()` will return the index of the - element as string (see example). - - @param[in] ref reference to a JSON value - @return iteration proxy object wrapping @a ref with an interface to use in - range-based for loops - - @liveexample{The following code shows how the wrapper is used,iterator_wrapper} - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @note The name of this function is not yet final and may change in the - future. - - @deprecated This stream operator is deprecated and will be removed in - future 4.0.0 of the library. Please use @ref items() instead; - that is, replace `json::iterator_wrapper(j)` with `j.items()`. - */ - JSON_DEPRECATED - static iteration_proxy iterator_wrapper(reference ref) noexcept - { - return ref.items(); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - JSON_DEPRECATED - static iteration_proxy iterator_wrapper(const_reference ref) noexcept - { - return ref.items(); - } - - /*! - @brief helper to access iterator member functions in range-based for - - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. - - For loop without `items()` function: - - @code{cpp} - for (auto it = j_object.begin(); it != j_object.end(); ++it) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - Range-based for loop without `items()` function: - - @code{cpp} - for (auto it : j_object) - { - // "it" is of type json::reference and has no key() member - std::cout << "value: " << it << '\n'; - } - @endcode - - Range-based for loop with `items()` function: - - @code{cpp} - for (auto it : j_object.items()) - { - std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; - } - @endcode - - @note When iterating over an array, `key()` will return the index of the - element as string (see example). For primitive types (e.g., numbers), - `key()` returns an empty string. - - @return iteration proxy object wrapping @a ref with an interface to use in - range-based for loops - - @liveexample{The following code shows how the function is used.,items} - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 3.x.x. - */ - iteration_proxy items() noexcept - { - return iteration_proxy(*this); - } - - /*! - @copydoc items() - */ - iteration_proxy items() const noexcept - { - return iteration_proxy(*this); - } - - /// @} - - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /*! - @brief checks whether the container is empty. - - Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `true` - boolean | `false` - string | `false` - number | `false` - object | result of function `object_t::empty()` - array | result of function `array_t::empty()` - - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `empty()` functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `begin() == end()`. - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - bool empty() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } - - default: - { - // all other types are nonempty - return false; - } - } - } - - /*! - @brief returns the number of elements - - Returns the number of elements in a JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` - boolean | `1` - string | `1` - number | `1` - object | result of function object_t::size() - array | result of function array_t::size() - - @liveexample{The following code calls `size()` on the different value - types.,size} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their size() functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `std::distance(begin(), end())`. - - @sa @ref empty() -- checks whether the container is empty - @sa @ref max_size() -- returns the maximal number of elements - - @since version 1.0.0 - */ - size_type size() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } - - default: - { - // all other types have size 1 - return 1; - } - } - } - - /*! - @brief returns the maximum possible number of elements - - Returns the maximum number of elements a JSON value is able to hold due to - system or library implementation limitations, i.e. `std::distance(begin(), - end())` for the JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` (same as `size()`) - boolean | `1` (same as `size()`) - string | `1` (same as `size()`) - number | `1` (same as `size()`) - object | result of function `object_t::max_size()` - array | result of function `array_t::max_size()` - - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `max_size()` functions have constant - complexity. - - @iterators No changes. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of returning `b.size()` where `b` is the largest - possible JSON value. - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - size_type max_size() const noexcept - { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } - - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /*! - @brief clears the contents - - Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called with the current value - type from @ref type(): - - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` - - @post Has the same effect as calling - @code {.cpp} - *this = basic_json(type()); - @endcode - - @liveexample{The example below shows the effect of `clear()` to different - JSON types.,clear} - - @complexity Linear in the size of the JSON value. - - @iterators All iterators, pointers and references related to this container - are invalidated. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @sa @ref basic_json(value_t) -- constructor that creates an object with the - same value than calling `clear()` - - @since version 1.0.0 - */ - void clear() noexcept - { - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_value.boolean = false; - break; - } - - case value_t::string: - { - m_value.string->clear(); - break; - } - - case value_t::array: - { - m_value.array->clear(); - break; - } - - case value_t::object: - { - m_value.object->clear(); - break; - } - - default: - break; - } - } - - /*! - @brief add an object to an array - - Appends the given element @a val to the end of the JSON value. If the - function is called on a JSON null value, an empty array is created before - appending @a val. - - @param[in] val the value to add to the JSON array - - @throw type_error.308 when called on a type other than JSON array or - null; example: `"cannot use push_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON array. Note how the `null` value was silently - converted to a JSON array.,push_back} - - @since version 1.0.0 - */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array - m_value.array->push_back(val); - } - - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - Inserts the given element @a val to the JSON object. If the function is - called on a JSON null value, an empty object is created before inserting - @a val. - - @param[in] val the value to add to the JSON object - - @throw type_error.308 when called on a type other than JSON object or - null; example: `"cannot use push_back() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON object. Note how the `null` value was silently - converted to a JSON object.,push_back__object_t__value} - - @since version 1.0.0 - */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (JSON_UNLIKELY(not(is_null() or is_object()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array - m_value.object->insert(val); - } - - /*! - @brief add an object to an object - @copydoc push_back(const typename object_t::value_type&) - */ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /*! - @brief add an object to an object - - This function allows to use `push_back` with an initializer list. In case - - 1. the current value is an object, - 2. the initializer list @a init contains only two elements, and - 3. the first element of @a init is a string, - - @a init is converted into an object element and added using - @ref push_back(const typename object_t::value_type&). Otherwise, @a init - is converted to a JSON value and added using @ref push_back(basic_json&&). - - @param[in] init an initializer list - - @complexity Linear in the size of the initializer list @a init. - - @note This function is required to resolve an ambiguous overload error, - because pairs like `{"key", "value"}` can be both interpreted as - `object_t::value_type` or `std::initializer_list`, see - https://github.com/nlohmann/json/issues/235 for more information. - - @liveexample{The example shows how initializer lists are treated as - objects when possible.,push_back__initializer_list} - */ - void push_back(initializer_list_t init) - { - if (is_object() and init.size() == 2 and (*init.begin())->is_string()) - { - basic_json&& key = init.begin()->moved_or_copied(); - push_back(typename object_t::value_type( - std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); - } - else - { - push_back(basic_json(init)); - } - } - - /*! - @brief add an object to an object - @copydoc push_back(initializer_list_t) - */ - reference operator+=(initializer_list_t init) - { - push_back(init); - return *this; - } - - /*! - @brief add an object to an array - - Creates a JSON value from the passed parameters @a args to the end of the - JSON value. If the function is called on a JSON null value, an empty array - is created before appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @throw type_error.311 when called on a type other than JSON array or - null; example: `"cannot use emplace_back() with number"` - - @complexity Amortized constant. - - @liveexample{The example shows how `push_back()` can be used to add - elements to a JSON array. Note how the `null` value was silently converted - to a JSON array.,emplace_back} - - @since version 2.0.8 - */ - template - void emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_array()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - m_value.array->emplace_back(std::forward(args)...); - } - - /*! - @brief add an object to an object if key does not exist - - Inserts a new element into a JSON object constructed in-place with the - given @a args if there is no element with the key in the container. If the - function is called on a JSON null value, an empty object is created before - appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @return a pair consisting of an iterator to the inserted element, or the - already-existing element if no insertion happened, and a bool - denoting whether the insertion took place. - - @throw type_error.311 when called on a type other than JSON object or - null; example: `"cannot use emplace() with number"` - - @complexity Logarithmic in the size of the container, O(log(`size()`)). - - @liveexample{The example shows how `emplace()` can be used to add elements - to a JSON object. Note how the `null` value was silently converted to a - JSON object. Further note how no value is added if there was already one - value stored with the same key.,emplace} - - @since version 2.0.8 - */ - template - std::pair emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (JSON_UNLIKELY(not(is_null() or is_object()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward(args)...); - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /*! - @brief inserts element - - Inserts element @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] val element to insert - @return iterator pointing to the inserted @a val. - - @throw type_error.309 if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @complexity Constant plus linear in the distance between @a pos and end of - the container. - - @liveexample{The example shows how `insert()` is used.,insert} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (JSON_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - /*! - @brief inserts element - @copydoc insert(const_iterator, const basic_json&) - */ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /*! - @brief inserts elements - - Inserts @a cnt copies of @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] cnt number of copies of @a val to insert - @param[in] val element to insert - @return iterator pointing to the first element inserted, or @a pos if - `cnt==0` - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @complexity Linear in @a cnt plus linear in the distance between @a pos - and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__count} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (JSON_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)` before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - @throw invalid_iterator.211 if @a first or @a last are iterators into - container for which insert is called; example: `"passed iterators may not - belong to container"` - - @return iterator pointing to the first element inserted, or @a pos if - `first==last` - - @complexity Linear in `std::distance(first, last)` plus linear in the - distance between @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__range} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (JSON_UNLIKELY(not is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - if (JSON_UNLIKELY(first.m_object == this)) - { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from initializer list @a ilist before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] ilist initializer list to insert the values from - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - - @return iterator pointing to the first element inserted, or @a pos if - `ilist` is empty - - @complexity Linear in `ilist.size()` plus linear in the distance between - @a pos and end of the container. - - @liveexample{The example shows how `insert()` is used.,insert__ilist} - - @since version 1.0.0 - */ - iterator insert(const_iterator pos, initializer_list_t ilist) - { - // insert only works for arrays - if (JSON_UNLIKELY(not is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if iterator pos fits to this JSON value - if (JSON_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from range `[first, last)`. - - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.309 if called on JSON values other than objects; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if iterator @a first or @a last does does not - point to an object; example: `"iterators first and last must point to - objects"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - - @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number - of elements to insert. - - @liveexample{The example shows how `insert()` is used.,insert__range_object} - - @since version 3.0.0 - */ - void insert(const_iterator first, const_iterator last) - { - // insert only works for objects - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - // passed iterators must belong to objects - if (JSON_UNLIKELY(not first.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); - } - - m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); - } - - /*! - @brief updates a JSON object from another object, overwriting existing keys - - Inserts all values from JSON object @a j and overwrites existing keys. - - @param[in] j JSON object to read values from - - @throw type_error.312 if called on JSON values other than objects; example: - `"cannot use update() with string"` - - @complexity O(N*log(size() + N)), where N is the number of elements to - insert. - - @liveexample{The example shows how `update()` is used.,update} - - @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - - @since version 3.0.0 - */ - void update(const_reference j) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); - } - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); - } - - for (auto it = j.cbegin(); it != j.cend(); ++it) - { - m_value.object->operator[](it.key()) = it.value(); - } - } - - /*! - @brief updates a JSON object from another object, overwriting existing keys - - Inserts all values from from range `[first, last)` and overwrites existing - keys. - - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert - - @throw type_error.312 if called on JSON values other than objects; example: - `"cannot use update() with string"` - @throw invalid_iterator.202 if iterator @a first or @a last does does not - point to an object; example: `"iterators first and last must point to - objects"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - - @complexity O(N*log(size() + N)), where N is the number of elements to - insert. - - @liveexample{The example shows how `update()` is used__range.,update} - - @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update - - @since version 3.0.0 - */ - void update(const_iterator first, const_iterator last) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_UNLIKELY(not is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); - } - - // check if range iterators belong to the same JSON object - if (JSON_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } - - // passed iterators must belong to objects - if (JSON_UNLIKELY(not first.m_object->is_object() - or not last.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); - } - - for (auto it = first; it != last; ++it) - { - m_value.object->operator[](it.key()) = it.value(); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of the JSON value with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other JSON value to exchange the contents with - - @complexity Constant. - - @liveexample{The example below shows how JSON values can be swapped with - `swap()`.,swap__reference} - - @since version 1.0.0 - */ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON array with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other array to exchange the contents with - - @throw type_error.310 when JSON value is not an array; example: `"cannot - use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how arrays can be swapped with - `swap()`.,swap__array_t} - - @since version 1.0.0 - */ - void swap(array_t& other) - { - // swap only works for arrays - if (JSON_LIKELY(is_array())) - { - std::swap(*(m_value.array), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON object with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other object to exchange the contents with - - @throw type_error.310 when JSON value is not an object; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how objects can be swapped with - `swap()`.,swap__object_t} - - @since version 1.0.0 - */ - void swap(object_t& other) - { - // swap only works for objects - if (JSON_LIKELY(is_object())) - { - std::swap(*(m_value.object), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /*! - @brief exchanges the values - - Exchanges the contents of a JSON string with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other string to exchange the contents with - - @throw type_error.310 when JSON value is not a string; example: `"cannot - use swap() with boolean"` - - @complexity Constant. - - @liveexample{The example below shows how strings can be swapped with - `swap()`.,swap__string_t} - - @since version 1.0.0 - */ - void swap(string_t& other) - { - // swap only works for strings - if (JSON_LIKELY(is_string())) - { - std::swap(*(m_value.string), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); - } - } - - /// @} - - public: - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - /*! - @brief comparison: equal - - Compares two JSON values for equality according to the following rules: - - Two JSON values are equal if (1) they are from the same type and (2) - their stored values are the same according to their respective - `operator==`. - - Integer and floating-point numbers are automatically converted before - comparison. Note than two NaN values are always treated as unequal. - - Two JSON null values are equal. - - @note Floating-point inside JSON values numbers are compared with - `json::number_float_t::operator==` which is `double::operator==` by - default. To compare floating-point while respecting an epsilon, an alternative - [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) - could be used, for instance - @code {.cpp} - template::value, T>::type> - inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept - { - return std::abs(a - b) <= epsilon; - } - @endcode - - @note NaN values never compare equal to themselves or to other NaN values. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are equal - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @complexity Linear. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__equal} - - @since version 1.0.0 - */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - return (*lhs.m_value.array == *rhs.m_value.array); - - case value_t::object: - return (*lhs.m_value.object == *rhs.m_value.object); - - case value_t::null: - return true; - - case value_t::string: - return (*lhs.m_value.string == *rhs.m_value.string); - - case value_t::boolean: - return (lhs.m_value.boolean == rhs.m_value.boolean); - - case value_t::number_integer: - return (lhs.m_value.number_integer == rhs.m_value.number_integer); - - case value_t::number_unsigned: - return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); - - case value_t::number_float: - return (lhs.m_value.number_float == rhs.m_value.number_float); - - default: - return false; - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); - } - - return false; - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs == basic_json(rhs)); - } - - /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) == rhs); - } - - /*! - @brief comparison: not equal - - Compares two JSON values for inequality by calculating `not (lhs == rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are not equal - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__notequal} - - @since version 1.0.0 - */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs != basic_json(rhs)); - } - - /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) != rhs); - } - - /*! - @brief comparison: less than - - Compares whether one JSON value @a lhs is less than another JSON value @a - rhs according to the following rules: - - If @a lhs and @a rhs have the same type, the values are compared using - the default `<` operator. - - Integer and floating-point numbers are automatically converted before - comparison - - In case @a lhs and @a rhs have different types, the values are ignored - and the order of the types is considered, see - @ref operator<(const value_t, const value_t). - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__less} - - @since version 1.0.0 - */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - return (*lhs.m_value.array) < (*rhs.m_value.array); - - case value_t::object: - return *lhs.m_value.object < *rhs.m_value.object; - - case value_t::null: - return false; - - case value_t::string: - return *lhs.m_value.string < *rhs.m_value.string; - - case value_t::boolean: - return lhs.m_value.boolean < rhs.m_value.boolean; - - case value_t::number_integer: - return lhs.m_value.number_integer < rhs.m_value.number_integer; - - case value_t::number_unsigned: - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - - case value_t::number_float: - return lhs.m_value.number_float < rhs.m_value.number_float; - - default: - return false; - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } - - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } - - /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs < basic_json(rhs)); - } - - /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) < rhs); - } - - /*! - @brief comparison: less than or equal - - Compares whether one JSON value @a lhs is less than or equal to another - JSON value by calculating `not (rhs < lhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than or equal to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greater} - - @since version 1.0.0 - */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return not (rhs < lhs); - } - - /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs <= basic_json(rhs)); - } - - /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) <= rhs); - } - - /*! - @brief comparison: greater than - - Compares whether one JSON value @a lhs is greater than another - JSON value by calculating `not (lhs <= rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__lessequal} - - @since version 1.0.0 - */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs <= rhs); - } - - /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs > basic_json(rhs)); - } - - /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) > rhs); - } - - /*! - @brief comparison: greater than or equal - - Compares whether one JSON value @a lhs is greater than or equal to another - JSON value by calculating `not (lhs < rhs)`. - - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than or equal to @a rhs - - @complexity Linear. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @liveexample{The example demonstrates comparing several JSON - types.,operator__greaterequal} - - @since version 1.0.0 - */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs < rhs); - } - - /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept - { - return (lhs >= basic_json(rhs)); - } - - /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) - */ - template::value, int>::type = 0> - friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept - { - return (basic_json(lhs) >= rhs); - } - - /// @} - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ - - /*! - @brief serialize to stream - - Serialize the given JSON value @a j to the output stream @a o. The JSON - value will be serialized using the @ref dump member function. - - - The indentation of the output can be controlled with the member variable - `width` of the output stream @a o. For instance, using the manipulator - `std::setw(4)` on @a o sets the indentation level to `4` and the - serialization result is the same as calling `dump(4)`. - - - The indentation character can be controlled with the member variable - `fill` of the output stream @a o. For instance, the manipulator - `std::setfill('\\t')` sets indentation to use a tab character rather than - the default space character. - - @param[in,out] o stream to serialize to - @param[in] j JSON value to serialize - - @return the stream @a o - - @throw type_error.316 if a string stored inside the JSON value is not - UTF-8 encoded - - @complexity Linear. - - @liveexample{The example below shows the serialization with different - parameters to `width` to adjust the indentation level.,operator_serialize} - - @since version 1.0.0; indentation character added in version 3.0.0 - */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - serializer s(detail::output_adapter(o), o.fill()); - s.dump(j, pretty_print, false, static_cast(indentation)); - return o; - } - - /*! - @brief serialize to stream - @deprecated This stream operator is deprecated and will be removed in - future 4.0.0 of the library. Please use - @ref operator<<(std::ostream&, const basic_json&) - instead; that is, replace calls like `j >> o;` with `o << j;`. - @since version 1.0.0; deprecated since version 3.0.0 - */ - JSON_DEPRECATED - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } - - /// @} - - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /*! - @brief deserialize from a compatible input - - This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @param[in] i input to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 if a parse error occurs; example: `""unexpected end - of input; expected string literal""` - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an array.,parse__array__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__string__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__istream__parser_callback_t} - - @liveexample{The example below demonstrates the `parse()` function reading - from a contiguous container.,parse__contiguouscontainer__parser_callback_t} - - @since version 2.0.3 (contiguous containers) - */ - static basic_json parse(detail::input_adapter i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - /*! - @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) - */ - static basic_json parse(detail::input_adapter& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - static bool accept(detail::input_adapter i) - { - return parser(i).accept(true); - } - - static bool accept(detail::input_adapter& i) - { - return parser(i).accept(true); - } - - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - @param[in] allow_exceptions whether to throw exceptions in case of a - parse error (optional, true by default) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); - return result; - } - - template::iterator_category>::value, int>::type = 0> - static bool accept(IteratorType first, IteratorType last) - { - return parser(detail::input_adapter(first, last)).accept(true); - } - - /*! - @brief deserialize from stream - @deprecated This stream operator is deprecated and will be removed in - version 4.0.0 of the library. Please use - @ref operator>>(std::istream&, basic_json&) - instead; that is, replace calls like `j << i;` with `i >> j;`. - @since version 1.0.0; deprecated since version 3.0.0 - */ - JSON_DEPRECATED - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - return operator>>(i, j); - } - - /*! - @brief deserialize from stream - - Deserializes an input stream to a JSON value. - - @param[in,out] i input stream to read a serialized JSON value from - @param[in,out] j JSON value to write the deserialized input to - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below shows how a JSON value is constructed by - reading a serialization from a stream.,operator_deserialize} - - @sa parse(std::istream&, const parser_callback_t) for a variant with a - parser callback function to filter values while parsing - - @since version 1.0.0 - */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - parser(detail::input_adapter(i)).parse(false, j); - return i; - } - - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /*! - @brief return the type as string - - Returns the type name as string to be used in error messages - usually to - indicate that a function was called on a wrong JSON type. - - @return a string representation of a the @a m_type member: - Value type | return value - ----------- | ------------- - null | `"null"` - boolean | `"boolean"` - string | `"string"` - number | `"number"` (for all number types) - object | `"object"` - array | `"array"` - discarded | `"discarded"` - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - - @complexity Constant. - - @liveexample{The following code exemplifies `type_name()` for all JSON - types.,type_name} - - @sa @ref type() -- return the type of the JSON value - @sa @ref operator value_t() -- return the type of the JSON value (implicit) - - @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` - since 3.0.0 - */ - const char* type_name() const noexcept - { - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; - } - } - } - - - private: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - public: - /*! - @brief create a CBOR serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the CBOR (Concise - Binary Object Representation) serialization format. CBOR is a binary - serialization format which aims to be more compact than JSON itself, yet - more efficient to parse. - - The library uses the following mapping from JSON values types to - CBOR types according to the CBOR specification (RFC 7049): - - JSON value type | value/range | CBOR type | first byte - --------------- | ------------------------------------------ | ---------------------------------- | --------------- - null | `null` | Null | 0xF6 - boolean | `true` | True | 0xF5 - boolean | `false` | False | 0xF4 - number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B - number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A - number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 - number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 - number_integer | -24..-1 | Negative integer | 0x20..0x37 - number_integer | 0..23 | Integer | 0x00..0x17 - number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A - number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_unsigned | 0..23 | Integer | 0x00..0x17 - number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A - number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B - number_float | *any value* | Double-Precision Float | 0xFB - string | *length*: 0..23 | UTF-8 string | 0x60..0x77 - string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 - string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 - string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A - string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B - array | *size*: 0..23 | array | 0x80..0x97 - array | *size*: 23..255 | array (1 byte follow) | 0x98 - array | *size*: 256..65535 | array (2 bytes follow) | 0x99 - array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A - array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B - object | *size*: 0..23 | map | 0xA0..0xB7 - object | *size*: 23..255 | map (1 byte follow) | 0xB8 - object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 - object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA - object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a CBOR value. - - @note If NaN or Infinity are stored inside a JSON number, they are - serialized properly. This behavior differs from the @ref dump() - function which serializes NaN or Infinity to `null`. - - @note The following CBOR types are not used in the conversion: - - byte strings (0x40..0x5F) - - UTF-8 strings terminated by "break" (0x7F) - - arrays terminated by "break" (0x9F) - - maps terminated by "break" (0xBF) - - date/time (0xC0..0xC1) - - bignum (0xC2..0xC3) - - decimal fraction (0xC4) - - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - - expected conversions (0xD5..0xD7) - - simple values (0xE0..0xF3, 0xF8) - - undefined (0xF7) - - half and single-precision floats (0xF9-0xFA) - - break (0xFF) - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in CBOR format.,to_cbor} - - @sa http://cbor.io - @sa @ref from_cbor(detail::input_adapter, const bool strict) for the - analogous deserialization - @sa @ref to_msgpack(const basic_json&) for the related MessagePack format - @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the - related UBJSON format - - @since version 2.0.9 - */ - static std::vector to_cbor(const basic_json& j) - { - std::vector result; - to_cbor(j, result); - return result; - } - - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the MessagePack - serialization format. MessagePack is a binary serialization format which - aims to be more compact than JSON itself, yet more efficient to parse. - - The library uses the following mapping from JSON values types to - MessagePack types according to the MessagePack specification: - - JSON value type | value/range | MessagePack type | first byte - --------------- | --------------------------------- | ---------------- | ---------- - null | `null` | nil | 0xC0 - boolean | `true` | true | 0xC3 - boolean | `false` | false | 0xC2 - number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 - number_integer | -2147483648..-32769 | int32 | 0xD2 - number_integer | -32768..-129 | int16 | 0xD1 - number_integer | -128..-33 | int8 | 0xD0 - number_integer | -32..-1 | negative fixint | 0xE0..0xFF - number_integer | 0..127 | positive fixint | 0x00..0x7F - number_integer | 128..255 | uint 8 | 0xCC - number_integer | 256..65535 | uint 16 | 0xCD - number_integer | 65536..4294967295 | uint 32 | 0xCE - number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF - number_unsigned | 0..127 | positive fixint | 0x00..0x7F - number_unsigned | 128..255 | uint 8 | 0xCC - number_unsigned | 256..65535 | uint 16 | 0xCD - number_unsigned | 65536..4294967295 | uint 32 | 0xCE - number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF - number_float | *any value* | float 64 | 0xCB - string | *length*: 0..31 | fixstr | 0xA0..0xBF - string | *length*: 32..255 | str 8 | 0xD9 - string | *length*: 256..65535 | str 16 | 0xDA - string | *length*: 65536..4294967295 | str 32 | 0xDB - array | *size*: 0..15 | fixarray | 0x90..0x9F - array | *size*: 16..65535 | array 16 | 0xDC - array | *size*: 65536..4294967295 | array 32 | 0xDD - object | *size*: 0..15 | fix map | 0x80..0x8F - object | *size*: 16..65535 | map 16 | 0xDE - object | *size*: 65536..4294967295 | map 32 | 0xDF - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a MessagePack value. - - @note The following values can **not** be converted to a MessagePack value: - - strings with more than 4294967295 bytes - - arrays with more than 4294967295 elements - - objects with more than 4294967295 elements - - @note The following MessagePack types are not used in the conversion: - - bin 8 - bin 32 (0xC4..0xC6) - - ext 8 - ext 32 (0xC7..0xC9) - - float 32 (0xCA) - - fixext 1 - fixext 16 (0xD4..0xD8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @note If NaN or Infinity are stored inside a JSON number, they are - serialized properly. This behavior differs from the @ref dump() - function which serializes NaN or Infinity to `null`. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in MessagePack format.,to_msgpack} - - @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&, const size_t) for the - analogous deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the - related UBJSON format - - @since version 2.0.9 - */ - static std::vector to_msgpack(const basic_json& j) - { - std::vector result; - to_msgpack(j, result); - return result; - } - - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - /*! - @brief create a UBJSON serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the UBJSON - (Universal Binary JSON) serialization format. UBJSON aims to be more compact - than JSON itself, yet more efficient to parse. - - The library uses the following mapping from JSON values types to - UBJSON types according to the UBJSON specification: - - JSON value type | value/range | UBJSON type | marker - --------------- | --------------------------------- | ----------- | ------ - null | `null` | null | `Z` - boolean | `true` | true | `T` - boolean | `false` | false | `F` - number_integer | -9223372036854775808..-2147483649 | int64 | `L` - number_integer | -2147483648..-32769 | int32 | `l` - number_integer | -32768..-129 | int16 | `I` - number_integer | -128..127 | int8 | `i` - number_integer | 128..255 | uint8 | `U` - number_integer | 256..32767 | int16 | `I` - number_integer | 32768..2147483647 | int32 | `l` - number_integer | 2147483648..9223372036854775807 | int64 | `L` - number_unsigned | 0..127 | int8 | `i` - number_unsigned | 128..255 | uint8 | `U` - number_unsigned | 256..32767 | int16 | `I` - number_unsigned | 32768..2147483647 | int32 | `l` - number_unsigned | 2147483648..9223372036854775807 | int64 | `L` - number_float | *any value* | float64 | `D` - string | *with shortest length indicator* | string | `S` - array | *see notes on optimized format* | array | `[` - object | *see notes on optimized format* | map | `{` - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a UBJSON value. - - @note The following values can **not** be converted to a UBJSON value: - - strings with more than 9223372036854775807 bytes (theoretical) - - unsigned integer numbers above 9223372036854775807 - - @note The following markers are not used in the conversion: - - `Z`: no-op values are not created. - - `C`: single-byte strings are serialized with `S` markers. - - @note Any UBJSON output created @ref to_ubjson can be successfully parsed - by @ref from_ubjson. - - @note If NaN or Infinity are stored inside a JSON number, they are - serialized properly. This behavior differs from the @ref dump() - function which serializes NaN or Infinity to `null`. - - @note The optimized formats for containers are supported: Parameter - @a use_size adds size information to the beginning of a container and - removes the closing marker. Parameter @a use_type further checks - whether all elements of a container have the same type and adds the - type marker to the beginning of the container. The @a use_type - parameter must only be used together with @a use_size = true. Note - that @a use_size = true alone may result in larger representations - - the benefit of this parameter is that the receiving side is - immediately informed on the number of elements of the container. - - @param[in] j JSON value to serialize - @param[in] use_size whether to add size annotations to container types - @param[in] use_type whether to add type annotations to container types - (must be combined with @a use_size = true) - @return UBJSON serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in UBJSON format.,to_ubjson} - - @sa http://ubjson.org - @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the - analogous deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - @sa @ref to_msgpack(const basic_json&) for the related MessagePack format - - @since version 3.1.0 - */ - static std::vector to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) - { - std::vector result; - to_ubjson(j, result, use_size, use_type); - return result; - } - - static void to_ubjson(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) - { - binary_writer(o).write_ubjson(j, use_size, use_type); - } - - static void to_ubjson(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) - { - binary_writer(o).write_ubjson(j, use_size, use_type); - } - - /*! - @brief create a JSON value from an input in CBOR format - - Deserializes a given input @a i to a JSON value using the CBOR (Concise - Binary Object Representation) serialization format. - - The library maps CBOR types to JSON value types as follows: - - CBOR type | JSON value type | first byte - ---------------------- | --------------- | ---------- - Integer | number_unsigned | 0x00..0x17 - Unsigned integer | number_unsigned | 0x18 - Unsigned integer | number_unsigned | 0x19 - Unsigned integer | number_unsigned | 0x1A - Unsigned integer | number_unsigned | 0x1B - Negative integer | number_integer | 0x20..0x37 - Negative integer | number_integer | 0x38 - Negative integer | number_integer | 0x39 - Negative integer | number_integer | 0x3A - Negative integer | number_integer | 0x3B - Negative integer | number_integer | 0x40..0x57 - UTF-8 string | string | 0x60..0x77 - UTF-8 string | string | 0x78 - UTF-8 string | string | 0x79 - UTF-8 string | string | 0x7A - UTF-8 string | string | 0x7B - UTF-8 string | string | 0x7F - array | array | 0x80..0x97 - array | array | 0x98 - array | array | 0x99 - array | array | 0x9A - array | array | 0x9B - array | array | 0x9F - map | object | 0xA0..0xB7 - map | object | 0xB8 - map | object | 0xB9 - map | object | 0xBA - map | object | 0xBB - map | object | 0xBF - False | `false` | 0xF4 - True | `true` | 0xF5 - Nill | `null` | 0xF6 - Half-Precision Float | number_float | 0xF9 - Single-Precision Float | number_float | 0xFA - Double-Precision Float | number_float | 0xFB - - @warning The mapping is **incomplete** in the sense that not all CBOR - types can be converted to a JSON value. The following CBOR types - are not supported and will yield parse errors (parse_error.112): - - byte strings (0x40..0x5F) - - date/time (0xC0..0xC1) - - bignum (0xC2..0xC3) - - decimal fraction (0xC4) - - bigfloat (0xC5) - - tagged items (0xC6..0xD4, 0xD8..0xDB) - - expected conversions (0xD5..0xD7) - - simple values (0xE0..0xF3, 0xF8) - - undefined (0xF7) - - @warning CBOR allows map keys of any type, whereas JSON only allows - strings as keys in object values. Therefore, CBOR maps with keys - other than UTF-8 strings are rejected (parse_error.113). - - @note Any CBOR output created @ref to_cbor can be successfully parsed by - @ref from_cbor. - - @param[in] i an input in CBOR format convertible to an input adapter - @param[in] strict whether to expect the input to be consumed until EOF - (true by default) - @return deserialized JSON value - - @throw parse_error.110 if the given input ends prematurely or the end of - file was not reached when @a strict was set to true - @throw parse_error.112 if unsupported features from CBOR were - used in the given input @a v or if the input is not valid CBOR - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the input @a i. - - @liveexample{The example shows the deserialization of a byte vector in CBOR - format to a JSON value.,from_cbor} - - @sa http://cbor.io - @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(detail::input_adapter, const bool) for the - related MessagePack format - @sa @ref from_ubjson(detail::input_adapter, const bool) for the related - UBJSON format - - @since version 2.0.9; parameter @a start_index since 2.1.1; changed to - consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0 - */ - static basic_json from_cbor(detail::input_adapter i, - const bool strict = true) - { - return binary_reader(i).parse_cbor(strict); - } - - /*! - @copydoc from_cbor(detail::input_adapter, const bool) - */ - template::value, int> = 0> - static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) - { - return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); - } - - /*! - @brief create a JSON value from an input in MessagePack format - - Deserializes a given input @a i to a JSON value using the MessagePack - serialization format. - - The library maps MessagePack types to JSON value types as follows: - - MessagePack type | JSON value type | first byte - ---------------- | --------------- | ---------- - positive fixint | number_unsigned | 0x00..0x7F - fixmap | object | 0x80..0x8F - fixarray | array | 0x90..0x9F - fixstr | string | 0xA0..0xBF - nil | `null` | 0xC0 - false | `false` | 0xC2 - true | `true` | 0xC3 - float 32 | number_float | 0xCA - float 64 | number_float | 0xCB - uint 8 | number_unsigned | 0xCC - uint 16 | number_unsigned | 0xCD - uint 32 | number_unsigned | 0xCE - uint 64 | number_unsigned | 0xCF - int 8 | number_integer | 0xD0 - int 16 | number_integer | 0xD1 - int 32 | number_integer | 0xD2 - int 64 | number_integer | 0xD3 - str 8 | string | 0xD9 - str 16 | string | 0xDA - str 32 | string | 0xDB - array 16 | array | 0xDC - array 32 | array | 0xDD - map 16 | object | 0xDE - map 32 | object | 0xDF - negative fixint | number_integer | 0xE0-0xFF - - @warning The mapping is **incomplete** in the sense that not all - MessagePack types can be converted to a JSON value. The following - MessagePack types are not supported and will yield parse errors: - - bin 8 - bin 32 (0xC4..0xC6) - - ext 8 - ext 32 (0xC7..0xC9) - - fixext 1 - fixext 16 (0xD4..0xD8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @param[in] i an input in MessagePack format convertible to an input - adapter - @param[in] strict whether to expect the input to be consumed until EOF - (true by default) - - @throw parse_error.110 if the given input ends prematurely or the end of - file was not reached when @a strict was set to true - @throw parse_error.112 if unsupported features from MessagePack were - used in the given input @a i or if the input is not valid MessagePack - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the input @a i. - - @liveexample{The example shows the deserialization of a byte vector in - MessagePack format to a JSON value.,from_msgpack} - - @sa http://msgpack.org - @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR - format - @sa @ref from_ubjson(detail::input_adapter, const bool) for the related - UBJSON format - - @since version 2.0.9; parameter @a start_index since 2.1.1; changed to - consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0 - */ - static basic_json from_msgpack(detail::input_adapter i, - const bool strict = true) - { - return binary_reader(i).parse_msgpack(strict); - } - - /*! - @copydoc from_msgpack(detail::input_adapter, const bool) - */ - template::value, int> = 0> - static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) - { - return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); - } - - /*! - @brief create a JSON value from an input in UBJSON format - - Deserializes a given input @a i to a JSON value using the UBJSON (Universal - Binary JSON) serialization format. - - The library maps UBJSON types to JSON value types as follows: - - UBJSON type | JSON value type | marker - ----------- | --------------------------------------- | ------ - no-op | *no value, next value is read* | `N` - null | `null` | `Z` - false | `false` | `F` - true | `true` | `T` - float32 | number_float | `d` - float64 | number_float | `D` - uint8 | number_unsigned | `U` - int8 | number_integer | `i` - int16 | number_integer | `I` - int32 | number_integer | `l` - int64 | number_integer | `L` - string | string | `S` - char | string | `C` - array | array (optimized values are supported) | `[` - object | object (optimized values are supported) | `{` - - @note The mapping is **complete** in the sense that any UBJSON value can - be converted to a JSON value. - - @param[in] i an input in UBJSON format convertible to an input adapter - @param[in] strict whether to expect the input to be consumed until EOF - (true by default) - - @throw parse_error.110 if the given input ends prematurely or the end of - file was not reached when @a strict was set to true - @throw parse_error.112 if a parse error occurs - @throw parse_error.113 if a string could not be parsed successfully - - @complexity Linear in the size of the input @a i. - - @liveexample{The example shows the deserialization of a byte vector in - UBJSON format to a JSON value.,from_ubjson} - - @sa http://ubjson.org - @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the - analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR - format - @sa @ref from_msgpack(detail::input_adapter, const bool) for the related - MessagePack format - - @since version 3.1.0 - */ - static basic_json from_ubjson(detail::input_adapter i, - const bool strict = true) - { - return binary_reader(i).parse_ubjson(strict); - } - - template::value, int> = 0> - static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) - { - return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_ubjson(strict); - } - - /// @} - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. Similar to @ref operator[](const typename - object_t::key_type&), `null` values are created in arrays and objects if - necessary. - - In particular: - - If the JSON pointer points to an object key that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. - - If the JSON pointer points to an array index that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. All indices between the current maximum and the given - index are also filled with `null`. - - The special value `-` is treated as a synonym for the index past the - end. - - @param[in] ptr a JSON pointer - - @return reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - - @liveexample{The behavior is shown in the example.,operatorjson_pointer} - - @since version 2.0.0 - */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. The function does not change the JSON - value; no `null` values are created. In particular, the the special value - `-` yields an exception. - - @param[in] ptr JSON pointer to the desired element - - @return const reference to the element pointed to by @a ptr - - @complexity Constant. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - - @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} - - @since version 2.0.0 - */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a reference to the element at with specified JSON pointer @a ptr, - with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. - - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. - - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. - - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. - - @throw out_of_range.403 if the JSON pointer describes a key of an object - which cannot be found. See example below. - - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 2.0.0 - - @liveexample{The behavior is shown in the example.,at_json_pointer} - */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - /*! - @brief access specified element via JSON Pointer - - Returns a const reference to the element at with specified JSON pointer @a - ptr, with bounds checking. - - @param[in] ptr JSON pointer to the desired element - - @return reference to the element pointed to by @a ptr - - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. - - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. - - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. - - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. - - @throw out_of_range.403 if the JSON pointer describes a key of an object - which cannot be found. See example below. - - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. - - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. - - @complexity Constant. - - @since version 2.0.0 - - @liveexample{The behavior is shown in the example.,at_json_pointer_const} - */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - /*! - @brief return flattened JSON value - - The function creates a JSON object whose keys are JSON pointers (see [RFC - 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all - primitive. The original JSON value can be restored using the @ref - unflatten() function. - - @return an object that maps JSON pointers to primitive values - - @note Empty objects and arrays are flattened to `null` and will not be - reconstructed correctly by the @ref unflatten() function. - - @complexity Linear in the size the JSON value. - - @liveexample{The following code shows how a JSON object is flattened to an - object whose keys consist of JSON pointers.,flatten} - - @sa @ref unflatten() for the reverse function - - @since version 2.0.0 - */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /*! - @brief unflatten a previously flattened JSON value - - The function restores the arbitrary nesting of a JSON value that has been - flattened before using the @ref flatten() function. The JSON value must - meet certain constraints: - 1. The value must be an object. - 2. The keys must be JSON pointers (see - [RFC 6901](https://tools.ietf.org/html/rfc6901)) - 3. The mapped values must be primitive JSON types. - - @return the original JSON from a flattened version - - @note Empty objects and arrays are flattened by @ref flatten() to `null` - values and can not unflattened to their original type. Apart from - this example, for a JSON value `j`, the following is always true: - `j == j.flatten().unflatten()`. - - @complexity Linear in the size the JSON value. - - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - - @liveexample{The following code shows how a flattened JSON object is - unflattened into the original nested JSON object.,unflatten} - - @sa @ref flatten() for the reverse function - - @since version 2.0.0 - */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /*! - @brief applies a JSON patch - - [JSON Patch](http://jsonpatch.com) defines a JSON document structure for - expressing a sequence of operations to apply to a JSON) document. With - this function, a JSON Patch is applied to the current JSON value by - executing all operations from the patch. - - @param[in] json_patch JSON patch document - @return patched document - - @note The application of a patch is atomic: Either all operations succeed - and the patched document is returned or an exception is thrown. In - any case, the original value is not changed: the patch is applied - to a copy of the value. - - @throw parse_error.104 if the JSON patch does not consist of an array of - objects - - @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` - - @throw out_of_range.401 if an array index is out of range. - - @throw out_of_range.403 if a JSON pointer inside the patch could not be - resolved successfully in the current JSON value; example: `"key baz not - found"` - - @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", - "move") - - @throw other_error.501 if "test" operation was unsuccessful - - @complexity Linear in the size of the JSON value and the length of the - JSON patch. As usually only a fraction of the JSON value is affected by - the patch, the complexity can usually be neglected. - - @liveexample{The following code shows how a JSON patch is applied to a - value.,patch} - - @sa @ref diff -- create a JSON patch by comparing two JSON values - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) - - @since version 2.0.0 - */ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string & op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.is_root()) - { - result = val; - } - else - { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = json_pointer::array_index(last_path); - if (JSON_UNLIKELY(static_cast(idx) > parent.size())) - { - // avoid undefined behavior - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } - } - break; - } - - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE - } - } - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (JSON_LIKELY(it != parent.end())) - { - parent.erase(it); - } - else - { - JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast(json_pointer::array_index(last_path))); - } - }; - - // type check: top level value must be an array - if (JSON_UNLIKELY(not json_patch.is_array())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); - } - - // iterate and apply the operations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json & - { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - - // check if desired value is present - if (JSON_UNLIKELY(it == val.m_value.object->end())) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); - } - - // check if result is of type string - if (JSON_UNLIKELY(string_type and not it->second.is_string())) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); - } - - // no error: return value - return it->second; - }; - - // type check: every element of the array must be an object - if (JSON_UNLIKELY(not val.is_object())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); - } - - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const std::string from_path = get_value("copy", "from", true); - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The copy is functionally identical to an "add" - // operation at the target location using the value - // specified in the "from" member. - operation_add(ptr, v); - break; - } - - case patch_operations::test: - { - bool success = false; - JSON_TRY - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - JSON_CATCH (out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (JSON_UNLIKELY(not success)) - { - JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); - } - - break; - } - - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); - } - } - } - - return result; - } - - /*! - @brief creates a diff as a JSON patch - - Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can - be changed into the value @a target by calling @ref patch function. - - @invariant For two JSON values @a source and @a target, the following code - yields always `true`: - @code {.cpp} - source.patch(diff(source, target)) == target; - @endcode - - @note Currently, only `remove`, `add`, and `replace` operations are - generated. - - @param[in] source JSON value to compare from - @param[in] target JSON value to compare against - @param[in] path helper value to create JSON pointers - - @return a JSON patch to convert the @a source to @a target - - @complexity Linear in the lengths of @a source and @a target. - - @liveexample{The following code shows how a JSON patch is created as a - diff for two JSON values.,diff} - - @sa @ref patch -- apply a JSON patch - @sa @ref merge_patch -- apply a JSON Merge Patch - - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - - @since version 2.0.0 - */ - static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - } - else - { - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - std::size_t i = 0; - while (i < source.size() and i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.cbegin(); it != source.cend(); ++it) - { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, {"path", path + "/" + key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.cbegin(); it != target.cend(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( - { - {"op", "add"}, {"path", path + "/" + key}, - {"value", it.value()} - }); - } - } - - break; - } - - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - break; - } - } - } - - return result; - } - - /// @} - - //////////////////////////////// - // JSON Merge Patch functions // - //////////////////////////////// - - /// @name JSON Merge Patch functions - /// @{ - - /*! - @brief applies a JSON Merge Patch - - The merge patch format is primarily intended for use with the HTTP PATCH - method as a means of describing a set of modifications to a target - resource's content. This function applies a merge patch to the current - JSON value. - - The function implements the following algorithm from Section 2 of - [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): - - ``` - define MergePatch(Target, Patch): - if Patch is an Object: - if Target is not an Object: - Target = {} // Ignore the contents and set it to an empty Object - for each Name/Value pair in Patch: - if Value is null: - if Name exists in Target: - remove the Name/Value pair from Target - else: - Target[Name] = MergePatch(Target[Name], Value) - return Target - else: - return Patch - ``` - - Thereby, `Target` is the current object; that is, the patch is applied to - the current value. - - @param[in] patch the patch to apply - - @complexity Linear in the lengths of @a patch. - - @liveexample{The following code shows how a JSON Merge Patch is applied to - a JSON document.,merge_patch} - - @sa @ref patch -- apply a JSON patch - @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) - - @since version 3.0.0 - */ - void merge_patch(const basic_json& patch) - { - if (patch.is_object()) - { - if (not is_object()) - { - *this = object(); - } - for (auto it = patch.begin(); it != patch.end(); ++it) - { - if (it.value().is_null()) - { - erase(it.key()); - } - else - { - operator[](it.key()).merge_patch(it.value()); - } - } - } - else - { - *this = patch; - } - } - - /// @} -}; -} // namespace nlohmann - -/////////////////////// -// nonmember support // -/////////////////////// - -// specialization of std::swap, and std::hash -namespace std -{ -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value - ) -{ - j1.swap(j2); -} - -/// hash value for JSON objects -template<> -struct hash -{ - /*! - @brief return a hash value for a JSON object - - @since version 1.0.0 - */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash(); - return h(j.dump()); - } -}; - -/// specialization for std::less -/// @note: do not remove the space after '<', -/// see https://github.com/nlohmann/json/pull/679 -template<> -struct less< ::nlohmann::detail::value_t> -{ - /*! - @brief compare two value_t enum values - @since version 3.0.0 - */ - bool operator()(nlohmann::detail::value_t lhs, - nlohmann::detail::value_t rhs) const noexcept - { - return nlohmann::detail::operator<(lhs, rhs); - } -}; - -} // namespace std - -/*! -@brief user-defined string literal for JSON values - -This operator implements a user-defined string literal for JSON objects. It -can be used by adding `"_json"` to a string literal and returns a JSON object -if no parse error occurred. - -@param[in] s a string representation of a JSON object -@param[in] n the length of string @a s -@return a JSON object - -@since version 1.0.0 -*/ -inline nlohmann::json operator "" _json(const char* s, std::size_t n) -{ - return nlohmann::json::parse(s, s + n); -} - -/*! -@brief user-defined string literal for JSON pointer - -This operator implements a user-defined string literal for JSON Pointers. It -can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer -object if no parse error occurred. - -@param[in] s a string representation of a JSON Pointer -@param[in] n the length of string @a s -@return a JSON pointer object - -@since version 2.0.0 -*/ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -// #include - - -// restore GCC/clang diagnostic settings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop -#endif -#if defined(__clang__) - #pragma GCC diagnostic pop -#endif - -// clean up -#undef JSON_CATCH -#undef JSON_THROW -#undef JSON_TRY -#undef JSON_LIKELY -#undef JSON_UNLIKELY -#undef JSON_DEPRECATED -#undef JSON_HAS_CPP_14 -#undef JSON_HAS_CPP_17 -#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION -#undef NLOHMANN_BASIC_JSON_TPL -#undef NLOHMANN_JSON_HAS_HELPER - - -#endif +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.1.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 1 +#define NLOHMANN_JSON_VERSION_PATCH 2 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +// #include + + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +// #include + +// #include + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ + static constexpr bool value = + not std::is_base_of::value and + not is_basic_json::value and + not is_basic_json_nested_type::value and + has_to_json::value; +}; + +template +struct is_compatible_type + : conjunction, + is_compatible_complete_type> +{ +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +// #include + + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_UNLIKELY(not j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_UNLIKELY(not j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + l.resize(j.size()); + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template < + typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type::value and + not std::is_same::value and + std::is_constructible < + BasicJsonType, typename CompatibleArrayType::value_type >::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); + } + + from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); + } + + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(obj, obj.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); + } +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +// #include + + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template::value or + std::is_same::value, + int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +// #include + + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + /// restore the last non-eof() character to input + virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ + public: + ~input_stream_adapter() override + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags + is.clear(); + } + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) + { + // skip byte order mark + std::char_traits::int_type c; + if ((c = get_character()) == 0xEF) + { + if ((c = get_character()) == 0xBB) + { + if ((c = get_character()) == 0xBF) + { + return; // Ignore BOM + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xBB'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); + } + is.putback('\xEF'); + } + else if (c != std::char_traits::eof()) + { + is.unget(); // no byte order mark; process as usual + } + } + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() override + { + return sb.sbumpc(); + } + + void unget_character() override + { + sb.sungetc(); // is.unget() avoided for performance + } + + private: + /// the associated input stream + std::istream& is; + std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ + public: + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l), start(b) + { + // skip byte order mark + if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') + { + cursor += 3; + } + } + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override + { + if (JSON_LIKELY(cursor < limit)) + { + return std::char_traits::to_int_type(*(cursor++)); + } + + return std::char_traits::eof(); + } + + void unget_character() noexcept override + { + if (JSON_LIKELY(cursor > start)) + { + --cursor; + } + } + + private: + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* limit; + /// pointer to the first character + const char* start; +}; + +class input_adapter +{ + public: + // native support + + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + input_adapter(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; + } + + private: + /// the actual adapter + input_adapter_t ia = nullptr; +}; +} +} + +// #include + + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + default: // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + + explicit lexer(detail::input_adapter_t adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer& operator=(lexer&) = delete; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + const auto factors = { 12, 8, 4, 0 }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' and current <= '9') + { + codepoint += ((current - 0x30) << factor); + } + else if (current >= 'A' and current <= 'F') + { + codepoint += ((current - 0x37) << factor); + } + else if (current >= 'a' and current <= 'f') + { + codepoint += ((current - 0x57) << factor); + } + else + { + return -1; + } + } + + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_LIKELY(*range <= current and current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + { + error_message = "invalid string: control character must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + assert(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + token_type scan_literal(const char* literal_text, const std::size_t length, + token_type return_type) + { + assert(current == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_UNLIKELY(get() != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + std::char_traits::int_type get() + { + ++chars_read; + current = ia->get_character(); + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + return current; + } + + /// unget current character (return it again on next get) + void unget() + { + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { + ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(int c) + { + token_buffer.push_back(std::char_traits::to_char_type(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t&& move_string() + { + return std::move(token_buffer); + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr std::size_t get_position() const noexcept + { + return chars_read; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters + std::stringstream ss; + ss << "(c) << ">"; + result += ss.str(); + } + else + { + // add character as is + result.push_back(c); + } + } + + return result; + } + + /// return syntax error message + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_literal("true", 4, token_type::literal_true); + case 'f': + return scan_literal("false", 5, token_type::literal_false); + case 'n': + return scan_literal("null", 4, token_type::literal_null); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + detail::input_adapter_t ia = nullptr; + + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; +}; +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + using parser_callback_t = + std::function; + + /// a parser reading from an input adapter + explicit parser(detail::input_adapter_t adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true) + : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + {} + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + // read first token + get_token(); + + parse_internal(true, result); + result.assert_invariant(); + + // in strict mode, input must be completely read + if (strict) + { + get_token(); + expect(token_type::end_of_input); + } + + // in case of an error, return discarded value + if (errored) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + // read first token + get_token(); + + if (not accept_internal()) + { + return false; + } + + // strict => last token must be EOF + return not strict or (get_token() == token_type::end_of_input); + } + + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse_internal(bool keep, BasicJsonType& result) + { + // never parse after a parse error was detected + assert(not errored); + + // start with a discarded value + if (not result.is_discarded()) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + + switch (last_token) + { + case token_type::begin_object: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::object_start, result); + } + + if (not callback or keep) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + string_t key; + BasicJsonType value; + while (true) + { + // store key + if (not expect(token_type::value_string)) + { + return; + } + key = m_lexer.move_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + BasicJsonType k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + if (not expect(token_type::name_separator)) + { + return; + } + + // parse and add value + get_token(); + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and keep_tag and not value.is_discarded()) + { + result.m_value.object->emplace(std::move(key), std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + if (not expect(token_type::end_object)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::begin_array: + { + if (keep) + { + if (callback) + { + keep = callback(depth++, parse_event_t::array_start, result); + } + + if (not callback or keep) + { + // explicitly set result to array to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + // parse values + BasicJsonType value; + while (true) + { + // parse value + value.m_value.destroy(value.m_type); + value.m_type = value_t::discarded; + parse_internal(keep, value); + + if (JSON_UNLIKELY(errored)) + { + return; + } + + if (keep and not value.is_discarded()) + { + result.m_value.array->push_back(std::move(value)); + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (not expect(token_type::end_array)) + { + return; + } + break; + } + + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + break; + } + + case token_type::literal_null: + { + result.m_type = value_t::null; + break; + } + + case token_type::value_string: + { + result.m_type = value_t::string; + result.m_value = m_lexer.move_string(); + break; + } + + case token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + break; + } + + case token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + break; + } + + case token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + if (allow_exceptions) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + + m_lexer.get_token_string() + "'")); + } + expect(token_type::uninitialized); + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + if (not expect(token_type::uninitialized)) + { + return; + } + break; // LCOV_EXCL_LINE + } + + default: + { + // the last token was unexpected; we expected a value + if (not expect(token_type::literal_or_value)) + { + return; + } + break; // LCOV_EXCL_LINE + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result.m_value.destroy(result.m_type); + result.m_type = value_t::discarded; + } + } + + /*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ + bool accept_internal() + { + switch (last_token) + { + case token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == token_type::end_object) + { + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + return (last_token == token_type::end_object); + } + } + + case token_type::begin_array: + { + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == token_type::end_array) + { + return true; + } + + // parse values + while (true) + { + // parse value + if (not accept_internal()) + { + return false; + } + + // comma -> next value + get_token(); + if (last_token == token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + return (last_token == token_type::end_array); + } + } + + case token_type::value_float: + { + // reject infinity or NAN + return std::isfinite(m_lexer.get_number_float()); + } + + case token_type::literal_false: + case token_type::literal_null: + case token_type::literal_true: + case token_type::value_integer: + case token_type::value_string: + case token_type::value_unsigned: + return true; + + default: // the last token was unexpected + return false; + } + } + + /// get next token from lexer + token_type get_token() + { + return (last_token = m_lexer.scan()); + } + + /*! + @throw parse_error.101 if expected token did not occur + */ + bool expect(token_type t) + { + if (JSON_UNLIKELY(t != last_token)) + { + errored = true; + expected = t; + if (allow_exceptions) + { + throw_exception(); + } + else + { + return false; + } + } + + return true; + } + + [[noreturn]] void throw_exception() const + { + std::string error_msg = "syntax error - "; + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether a syntax error occurred + bool errored = false; + /// possible reason for the syntax error + token_type expected = token_type::uninitialized; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) noexcept + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) noexcept + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; +} +} + +// #include + + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} +} + +// #include + + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// allow basic_json to access private members + friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + friend BasicJsonType; + friend iteration_proxy; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) {} + + /*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + + default: + { + if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (JSON_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it; +}; +} +} + +// #include + + +#include // size_t +#include // string, to_string + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + std::string key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + return std::to_string(array_index); + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return ""; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} +} + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) : v(vec) {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + + void write_character(CharType c) override + { + stream.put(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) : str(s) {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using string_t = typename BasicJsonType::string_t; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_cbor(const bool strict) + { + const auto res = parse_cbor_internal(); + if (strict) + { + get(); + expect_eof(); + } + return res; + } + + /*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_msgpack(const bool strict) + { + const auto res = parse_msgpack_internal(); + if (strict) + { + get(); + expect_eof(); + } + return res; + } + + /*! + @brief create a JSON value from UBJSON input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from UBJSON input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ + BasicJsonType parse_ubjson(const bool strict) + { + const auto res = parse_ubjson_internal(); + if (strict) + { + get_ignore_noop(); + expect_eof(); + } + return res; + } + + /*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static constexpr bool little_endianess(int num = 1) noexcept + { + return (*reinterpret_cast(&num) == 1); + } + + private: + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_cbor_internal(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return static_cast(current); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + return get_number(); + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + return get_number(); + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + return get_number(); + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + return get_number(); + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return static_cast(0x20 - 1 - current); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - + static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + return get_cbor_array(current & 0x1F); + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + return get_cbor_array(get_number()); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + return get_cbor_array(get_number()); + } + + case 0x9F: // array (indefinite length) + { + BasicJsonType result = value_t::array; + while (get() != 0xFF) + { + result.push_back(parse_cbor_internal(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + { + return get_cbor_object(current & 0x1F); + } + + case 0xB8: // map (one-byte uint8_t for n follows) + { + return get_cbor_object(get_number()); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + return get_cbor_object(get_number()); + } + + case 0xBF: // map (indefinite length) + { + BasicJsonType result = value_t::object; + while (get() != 0xFF) + { + auto key = get_cbor_string(); + result[key] = parse_cbor_internal(); + } + return result; + } + + case 0xF4: // false + { + return false; + } + + case 0xF5: // true + { + return true; + } + + case 0xF6: // null + { + return value_t::null; + } + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + unexpect_eof(); + const int byte2 = get(); + unexpect_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1F; + const int mant = half & 0x3FF; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = (mant == 0) ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + BasicJsonType parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return static_cast(current); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + { + return get_msgpack_object(current & 0x0F); + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + { + return get_msgpack_array(current & 0x0F); + } + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + return get_msgpack_string(); + + case 0xC0: // nil + return value_t::null; + + case 0xC2: // false + return false; + + case 0xC3: // true + return true; + + case 0xCA: // float 32 + return get_number(); + + case 0xCB: // float 64 + return get_number(); + + case 0xCC: // uint 8 + return get_number(); + + case 0xCD: // uint 16 + return get_number(); + + case 0xCE: // uint 32 + return get_number(); + + case 0xCF: // uint 64 + return get_number(); + + case 0xD0: // int 8 + return get_number(); + + case 0xD1: // int 16 + return get_number(); + + case 0xD2: // int 32 + return get_number(); + + case 0xD3: // int 64 + return get_number(); + + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + return get_msgpack_string(); + + case 0xDC: // array 16 + { + return get_msgpack_array(get_number()); + } + + case 0xDD: // array 32 + { + return get_msgpack_array(get_number()); + } + + case 0xDE: // map 16 + { + return get_msgpack_object(get_number()); + } + + case 0xDF: // map 32 + { + return get_msgpack_object(get_number()); + } + + // positive fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return static_cast(current); + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ + BasicJsonType parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + int get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ + template NumberType get_number() + { + // step 1: read input into array with system's byte order + std::array vec; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + unexpect_eof(); + + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + NumberType result; + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + template + string_t get_string(const NumberType len) + { + string_t result; + std::generate_n(std::back_inserter(result), len, [this]() + { + get(); + unexpect_eof(); + return static_cast(current); + }); + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_cbor_string() + { + unexpect_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(current & 0x1F); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + return get_string(get_number()); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + return get_string(get_number()); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + return get_string(get_number()); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + return get_string(get_number()); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + string_t result; + while (get() != 0xFF) + { + result.append(get_cbor_string()); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_cbor_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_cbor_internal(); + }); + return result; + } + + template + BasicJsonType get_cbor_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_cbor_string(); + auto val = parse_cbor_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_msgpack_string() + { + unexpect_eof(); + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(current & 0x1F); + } + + case 0xD9: // str 8 + { + return get_string(get_number()); + } + + case 0xDA: // str 16 + { + return get_string(get_number()); + } + + case 0xDB: // str 32 + { + return get_string(get_number()); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + template + BasicJsonType get_msgpack_array(const NumberType len) + { + BasicJsonType result = value_t::array; + std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() + { + return parse_msgpack_internal(); + }); + return result; + } + + template + BasicJsonType get_msgpack_object(const NumberType len) + { + BasicJsonType result = value_t::object; + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + len, [this]() + { + get(); + auto key = get_msgpack_string(); + auto val = parse_msgpack_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + return result; + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ + string_t get_ubjson_string(const bool get_char = true) + { + if (get_char) + { + get(); // TODO: may we ignore N here? + } + + unexpect_eof(); + + switch (current) + { + case 'U': + return get_string(get_number()); + case 'i': + return get_string(get_number()); + case 'I': + return get_string(get_number()); + case 'l': + return get_string(get_number()); + case 'L': + return get_string(get_number()); + default: + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "expected a UBJSON string; last byte: 0x" + ss.str())); + } + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @return pair of the size and the type + */ + std::pair get_ubjson_size_type() + { + std::size_t sz = string_t::npos; + int tc = 0; + + get_ignore_noop(); + + if (current == '$') + { + tc = get(); // must not ignore 'N', because 'N' maybe the type + unexpect_eof(); + + get_ignore_noop(); + if (current != '#') + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "expected '#' after UBJSON type information; last byte: 0x" + ss.str())); + } + sz = parse_ubjson_internal(); + } + else if (current == '#') + { + sz = parse_ubjson_internal(); + } + + return std::make_pair(sz, tc); + } + + BasicJsonType get_ubjson_value(const int prefix) + { + switch (prefix) + { + case std::char_traits::eof(): // EOF + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + + case 'T': // true + return true; + case 'F': // false + return false; + + case 'Z': // null + return nullptr; + + case 'U': + return get_number(); + case 'i': + return get_number(); + case 'I': + return get_number(); + case 'l': + return get_number(); + case 'L': + return get_number(); + case 'd': + return get_number(); + case 'D': + return get_number(); + + case 'C': // char + { + get(); + unexpect_eof(); + if (JSON_UNLIKELY(current > 127)) + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, + "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str())); + } + return string_t(1, static_cast(current)); + } + + case 'S': // string + return get_ubjson_string(); + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, + "error reading UBJSON; last byte: 0x" + ss.str())); + } + } + + BasicJsonType get_ubjson_array() + { + BasicJsonType result = value_t::array; + const auto size_and_type = get_ubjson_size_type(); + + if (size_and_type.first != string_t::npos) + { + if (JSON_UNLIKELY(size_and_type.first > result.max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive array size: " + std::to_string(size_and_type.first))); + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + std::generate_n(std::back_inserter(*result.m_value.array), + size_and_type.first, [this, size_and_type]() + { + return get_ubjson_value(size_and_type.second); + }); + } + } + else + { + std::generate_n(std::back_inserter(*result.m_value.array), + size_and_type.first, [this]() + { + return parse_ubjson_internal(); + }); + } + } + else + { + while (current != ']') + { + result.push_back(parse_ubjson_internal(false)); + get_ignore_noop(); + } + } + + return result; + } + + BasicJsonType get_ubjson_object() + { + BasicJsonType result = value_t::object; + const auto size_and_type = get_ubjson_size_type(); + + if (size_and_type.first != string_t::npos) + { + if (JSON_UNLIKELY(size_and_type.first > result.max_size())) + { + JSON_THROW(out_of_range::create(408, + "excessive object size: " + std::to_string(size_and_type.first))); + } + + if (size_and_type.second != 0) + { + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + size_and_type.first, [this, size_and_type]() + { + auto key = get_ubjson_string(); + auto val = get_ubjson_value(size_and_type.second); + return std::make_pair(std::move(key), std::move(val)); + }); + } + else + { + std::generate_n(std::inserter(*result.m_value.object, + result.m_value.object->end()), + size_and_type.first, [this]() + { + auto key = get_ubjson_string(); + auto val = parse_ubjson_internal(); + return std::make_pair(std::move(key), std::move(val)); + }); + } + } + else + { + while (current != '}') + { + auto key = get_ubjson_string(false); + result[std::move(key)] = parse_ubjson_internal(); + get_ignore_noop(); + } + } + + return result; + } + + /*! + @brief throw if end of input is not reached + @throw parse_error.110 if input not ended + */ + void expect_eof() const + { + if (JSON_UNLIKELY(current != std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); + } + } + + /*! + @briefthrow if end of input is reached + @throw parse_error.110 if input ended + */ + void unexpect_eof() const + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + } + + private: + /// input adapter + input_adapter_t ia = nullptr; + + /// the current character + int current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); +}; +} +} + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(static_cast(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? static_cast(0xF5) + : static_cast(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(static_cast(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(static_cast(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: // Double-Precision Float + { + oa->write_character(static_cast(0xFB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(static_cast(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(static_cast(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? static_cast(0xC3) + : static_cast(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(static_cast(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(static_cast(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(static_cast(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(static_cast(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(static_cast(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(static_cast(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(static_cast(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(static_cast(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: // float 64 + { + oa->write_character(static_cast(0xCB)); + write_number(j.m_value.number_float); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(static_cast(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(static_cast(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(static_cast(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(static_cast(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(static_cast(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(static_cast(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(static_cast(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true) + { + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(static_cast('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + oa->write_character(j.m_value.boolean + ? static_cast('T') + : static_cast('F')); + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(static_cast('S')); + } + write_number_with_ubjson_prefix(j.m_value.string->size(), true); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(static_cast('[')); + } + + bool prefix_required = true; + if (use_type and not j.m_value.array->empty()) + { + assert(use_count); + const char first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(static_cast('$')); + oa->write_character(static_cast(first_prefix)); + } + } + + if (use_count) + { + oa->write_character(static_cast('#')); + write_number_with_ubjson_prefix(j.m_value.array->size(), true); + } + + for (const auto& el : *j.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required); + } + + if (not use_count) + { + oa->write_character(static_cast(']')); + } + + break; + } + + case value_t::object: + { + if (add_prefix) + { + oa->write_character(static_cast('{')); + } + + bool prefix_required = true; + if (use_type and not j.m_value.object->empty()) + { + assert(use_count); + const char first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(static_cast('$')); + oa->write_character(static_cast(first_prefix)); + } + } + + if (use_count) + { + oa->write_character(static_cast('#')); + write_number_with_ubjson_prefix(j.m_value.object->size(), true); + } + + for (const auto& el : *j.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required); + } + + if (not use_count) + { + oa->write_character(static_cast('}')); + } + + break; + } + + default: + break; + } + } + + private: + /* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(const NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (add_prefix) + { + oa->write_character(static_cast('D')); // float64 + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + } + + // UBJSON: write number (signed integer) + template::value and + not std::is_floating_point::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n and n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + + @note This function does not need to be 100% accurate when it comes to + integer limits. In case a number exceeds the limits of int64_t, + this will be detected by a later call to function + write_number_with_ubjson_prefix. Therefore, we return 'L' for any + value that does not fit the previous limits. + */ + char ubjson_prefix(const BasicJsonType& j) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + else // no check and assume int64_t (see note above) + { + return 'L'; + } + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'i'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'U'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'I'; + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + return 'l'; + } + else // no check and assume int64_t (see note above) + { + return 'L'; + } + } + + case value_t::number_float: + return 'D'; + + case value_t::string: + return 'S'; + + case value_t::array: + return '['; + + case value_t::object: + return '{'; + + default: // discarded values + return 'N'; + } + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = binary_reader::little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // setfill +#include // next +#include // numeric_limits +#include // string +#include // stringstream +#include // is_same + +// #include + +// #include + + +#include // assert +#include // or, and, not +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + uint64_t f; + int e; + + constexpr diyfp() noexcept : f(0), e(0) {} + constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + assert(x.e == y.e); + assert(x.f >= y.f); + + return diyfp(x.f - y.f, x.e); + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const uint64_t u_lo = x.f & 0xFFFFFFFF; + const uint64_t u_hi = x.f >> 32; + const uint64_t v_lo = y.f & 0xFFFFFFFF; + const uint64_t v_hi = y.f >> 32; + + const uint64_t p0 = u_lo * v_lo; + const uint64_t p1 = u_lo * v_hi; + const uint64_t p2 = u_hi * v_lo; + const uint64_t p3 = u_hi * v_hi; + + const uint64_t p0_hi = p0 >> 32; + const uint64_t p1_lo = p1 & 0xFFFFFFFF; + const uint64_t p1_hi = p1 >> 32; + const uint64_t p2_lo = p2 & 0xFFFFFFFF; + const uint64_t p2_hi = p2 >> 32; + + uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += uint64_t{1} << (64 - 32 - 1); // round, ties up + + const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); + + return diyfp(h, x.e + y.e + 64); + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + assert(x.f != 0); + + while ((x.f >> 63) == 0) + { + x.f <<= 1; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + assert(delta >= 0); + assert(((x.f << delta) >> delta) == x.f); + + return diyfp(x.f << delta, target_exponent); + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + assert(std::isfinite(value)); + assert(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; + + const uint64_t bits = reinterpret_bits(value); + const uint64_t E = bits >> (kPrecision - 1); + const uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = (E == 0); + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = (F == 0 and E > 1); + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersSize = 79; + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr cached_power kCachedPowers[] = + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + assert(e >= -1500); + assert(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + (f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + assert(index >= 0); + assert(index < kCachedPowersSize); + static_cast(kCachedPowersSize); // Fix warning. + + const cached_power cached = kCachedPowers[index]; + assert(kAlpha <= cached.e + e + 64); + assert(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + else if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + else if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + else if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + else if (n >= 100000) + { + pow10 = 100000; + return 6; + } + else if (n >= 10000) + { + pow10 = 10000; + return 5; + } + else if (n >= 1000) + { + pow10 = 1000; + return 4; + } + else if (n >= 100) + { + pow10 = 100; + return 3; + } + else if (n >= 10) + { + pow10 = 10; + return 2; + } + else + { + pow10 = 1; + return 1; + } +} + +inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, + uint64_t rest, uint64_t ten_k) +{ + assert(len >= 1); + assert(dist <= delta); + assert(rest <= delta); + assert(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + and delta - rest >= ten_k + and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) + { + assert(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + assert(M_plus.e >= kAlpha); + assert(M_plus.e <= kGamma); + + uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); + + uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + assert(p1 > 0); + + uint32_t pow10; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + assert(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const uint64_t rest = (uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const uint64_t ten_n = uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + assert(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + assert(p2 <= UINT64_MAX / 10); + p2 *= 10; + const uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + assert(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + assert(m_plus.e == m_minus.e); + assert(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + assert(std::isfinite(value)); + assert(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +inline char* append_exponent(char* buf, int e) +{ + assert(e > -1000); + assert(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + uint32_t k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + assert(min_exp < 0); + assert(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n and n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n - k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (n + 2); + } + + if (0 < n and n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + assert(k > n); + + std::memmove(buf + (n + 1), buf + n, static_cast(k - n)); + buf[n] = '.'; + return buf + (k + 1); + } + + if (min_exp < n and n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + -n), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2 + (-n) + k); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k - 1)); + buf[1] = '.'; + buf += 1 + k; + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +char* to_chars(char* first, char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + assert(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } + + assert(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + assert(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + assert(last - first >= kMaxExp + 2); + assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + assert(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + static constexpr uint8_t UTF8_ACCEPT = 0; + static constexpr uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(std::move(s)), loc(std::localeconv()), + thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), + decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), + indent_char(ichar), indent_string(512, indent_char) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(i != val.m_value.object->cend()); + assert(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } + } + + private: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + uint32_t codepoint; + uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint)); + bytes += 6; + } + else + { + std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0 + (codepoint >> 10)), + static_cast(0xDC00 + (codepoint & 0x3FF))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + } + + default: // decode found yet incomplete multi-byte code point + { + if (not ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + break; + } + } + } + + if (JSON_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + std::stringstream ss; + ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + } + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template::value or + std::is_same::value, + int> = 0> + void dump_integer(NumberType x) + { + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + std::size_t i = 0; + + while (x != 0) + { + // spare 1 byte for '\0' + assert(i < number_buffer.size() - 1); + + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } + + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (not std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 24 and std::numeric_limits::max_exponent == 128) or + (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 53 and std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + char* begin = number_buffer.data(); + char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), + number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return (c == '.' or c == 'e'); + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..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, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 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, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + const uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6) + : static_cast(0xff >> type) & (byte); + + state = utf8d[256u + state * 16u + type]; + return state; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; +}; +} +} + +// #include + + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) + {} + + json_ref(const value_type& value) + : value_ref(const_cast(&value)), is_rvalue(false) + {} + + json_ref(std::initializer_list init) + : owned_value(init), value_ref(&owned_value), is_rvalue(true) + {} + + template + json_ref(Args&& ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) + {} + + // class should be movable only + json_ref(json_ref&&) = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + + value_type moved_or_copied() const + { + if (is_rvalue) + { + return std::move(*value_ref); + } + return *value_ref; + } + + value_type const& operator*() const + { + return *static_cast(value_ref); + } + + value_type const* operator->() const + { + return static_cast(value_ref); + } + + private: + mutable value_type owned_value = nullptr; + value_type* value_ref = nullptr; + const bool is_rvalue; +}; +} +} + +// #include + + +#include // assert +#include // accumulate +#include // string +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ + static int array_index(const std::string& s) + { + std::size_t processed_chars = 0; + const int res = std::stoi(s, &processed_chars); + + // check if the string was completely read + if (JSON_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); + } + + return res; + } + + private: + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + std::string pop_back() + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (JSON_UNLIKELY(is_root())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + BasicJsonType& get_and_create(BasicJsonType& j) const + { + using size_type = typename BasicJsonType::size_type; + auto result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + JSON_TRY + { + result = &result->operator[](static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == detail::value_t::null) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const char x) + { + return (x >= '0' and x <= '9'); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums or reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // use unchecked array access + JSON_TRY + { + ptr = &ptr->operator[]( + static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + using size_type = typename BasicJsonType::size_type; + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, + "array index '" + reference_token + + "' must not begin with '0'")); + } + + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(array_index(reference_token))); + } + JSON_CATCH(std::invalid_argument&) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } + + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + + return *ptr; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, + "JSON pointer must be empty or begin with '/' - was: '" + + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_UNLIKELY(pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, const std::string& f, + const std::string& t) + { + assert(not f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} + } + + /// escape "~"" to "~0" and "/" to "~1" + static std::string escape(std::string s) + { + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape "~1" to tilde and "~0" to slash (order is important!) + static void unescape(std::string& s) + { + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.m_type) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_UNLIKELY(not value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_UNLIKELY(not element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return (lhs.reference_tokens == rhs.reference_tokens); + } + + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return not (lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens; +}; +} + +// #include + + +#include + +// #include + +// #include + + +namespace nlohmann +{ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + friend ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer; + using parser = ::nlohmann::detail::parser; + + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// @copydoc nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_PATCH); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, it is unspecified which + one of the values for a given key will be chosen. For instance, + `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or + `{"key": 2}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * object) + { + AllocatorTraits::deallocate(alloc, object, 1); + }; + std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + void destroy(value_t t) noexcept + { + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + default: + { + break; + } + } + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const noexcept + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ + using parse_event_t = typename parser::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = typename parser::parser_callback_t; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template , + detail::enable_if_t< + detail::is_compatible_type::value, int> = 0> + basic_json(CompatibleType && val) noexcept(noexcept( + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.1.2 + */ + template ::value and not std::is_same::value, int> = 0> + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + } + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); + }); + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + assert_invariant(); + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } + + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + + std::string(first.m_object->type_name()))); + } + + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /// @private + basic_json(const detail::json_ref& ref) + : basic_json(ref.moved_or_copied()) + {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + break; + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() noexcept + { + assert_invariant(); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ + string_t dump(const int indent = -1, const char indent_char = ' ', + const bool ensure_ascii = false) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return (m_type == value_t::null); + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return (m_type == value_t::boolean); + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return (m_type == value_t::number_unsigned); + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return (m_type == value_t::number_float); + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return (m_type == value_t::object); + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return (m_type == value_t::array); + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return (m_type == value_t::string); + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return (m_type == value_t::discarded); + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr::type>(); + + if (JSON_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::type, basic_json_t>::value, + int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.1.2 + */ + template::value and + detail::is_basic_json::value, int> = 0> + BasicJsonType get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template, + detail::enable_if_t < + not detail::is_basic_json::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same>::value and + not std::is_same::value and + not detail::is_basic_json::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) + and not std::is_same::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->operator[](key); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() + or not last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_LIKELY(is_array())) + { + if (JSON_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ + JSON_DEPRECATED + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + JSON_DEPRECATED + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.x.x. + */ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() and init.size() == 2 and (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ + template + void emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_UNLIKELY(not(is_null() or is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (JSON_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_UNLIKELY(not is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if iterator pos fits to this JSON value + if (JSON_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + if (JSON_UNLIKELY(not j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_UNLIKELY(not is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); + } + + // check if range iterators belong to the same JSON object + if (JSON_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + // passed iterators must belong to objects + if (JSON_UNLIKELY(not first.m_object->is_object() + or not last.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (JSON_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (JSON_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (JSON_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array == *rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object == *rhs.m_value.object); + + case value_t::null: + return true; + + case value_t::string: + return (*lhs.m_value.string == *rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean == rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer == rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float == rhs.m_value.number_float); + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return *lhs.m_value.object < *rhs.m_value.object; + + case value_t::null: + return false; + + case value_t::string: + return *lhs.m_value.string < *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean < rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer < rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float < rhs.m_value.number_float; + + default: + return false; + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs < basic_json(rhs)); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) < rhs); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs <= basic_json(rhs)); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) <= rhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs > basic_json(rhs)); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) > rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs >= basic_json(rhs)); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) >= rhs); + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ + static basic_json parse(detail::input_adapter i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + /*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ + static basic_json parse(detail::input_adapter& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(i, cb, allow_exceptions).parse(true, result); + return result; + } + + static bool accept(detail::input_adapter i) + { + return parser(i).accept(true); + } + + static bool accept(detail::input_adapter& i) + { + return parser(i).accept(true); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); + return result; + } + + template::iterator_category>::value, int>::type = 0> + static bool accept(IteratorType first, IteratorType last) + { + return parser(detail::input_adapter(first, last)).accept(true); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + - unsigned integer numbers above 9223372036854775807 + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_cbor(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_cbor(strict); + } + + /*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ + static basic_json from_msgpack(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_msgpack(strict); + } + + /*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ + template::value, int> = 0> + static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); + } + + /*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_msgpack(detail::input_adapter, const bool) for the related + MessagePack format + + @since version 3.1.0 + */ + static basic_json from_ubjson(detail::input_adapter i, + const bool strict = true) + { + return binary_reader(i).parse_ubjson(strict); + } + + template::value, int> = 0> + static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) + { + return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_ubjson(strict); + } + + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_UNLIKELY(static_cast(idx) > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(json_pointer::array_index(last_path))); + } + }; + + // type check: top level value must be an array + if (JSON_UNLIKELY(not json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_UNLIKELY(it == val.m_value.object->end())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (JSON_UNLIKELY(string_type and not it->second.is_string())) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_UNLIKELY(not val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_UNLIKELY(not success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ + void merge_patch(const basic_json& patch) + { + if (patch.is_object()) + { + if (not is_object()) + { + *this = object(); + } + for (auto it = patch.begin(); it != patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = patch; + } + } + + /// @} +}; +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif +#if defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + + +#endif diff --git a/libs/nxpy/LICENSE.md b/libs/nxpy/LICENSE.md index bade95b1..38203c36 100644 --- a/libs/nxpy/LICENSE.md +++ b/libs/nxpy/LICENSE.md @@ -1,5 +1,5 @@ -Copyright 2018 PyNX Authors - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +Copyright 2018 PyNX Authors + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/libs/nxpy/include/Python-ast.h b/libs/nxpy/include/Python-ast.h index 2d3eacb9..8202a448 100644 --- a/libs/nxpy/include/Python-ast.h +++ b/libs/nxpy/include/Python-ast.h @@ -1,601 +1,601 @@ -/* File automatically generated by Parser/asdl_c.py. */ - -#include "asdl.h" - -typedef struct _mod *mod_ty; - -typedef struct _stmt *stmt_ty; - -typedef struct _expr *expr_ty; - -typedef enum _expr_context { Load=1, Store=2, Del=3, AugLoad=4, AugStore=5, - Param=6 } expr_context_ty; - -typedef struct _slice *slice_ty; - -typedef enum _boolop { And=1, Or=2 } boolop_ty; - -typedef enum _operator { Add=1, Sub=2, Mult=3, MatMult=4, Div=5, Mod=6, Pow=7, - LShift=8, RShift=9, BitOr=10, BitXor=11, BitAnd=12, - FloorDiv=13 } operator_ty; - -typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty; - -typedef enum _cmpop { Eq=1, NotEq=2, Lt=3, LtE=4, Gt=5, GtE=6, Is=7, IsNot=8, - In=9, NotIn=10 } cmpop_ty; - -typedef struct _comprehension *comprehension_ty; - -typedef struct _excepthandler *excepthandler_ty; - -typedef struct _arguments *arguments_ty; - -typedef struct _arg *arg_ty; - -typedef struct _keyword *keyword_ty; - -typedef struct _alias *alias_ty; - -typedef struct _withitem *withitem_ty; - - -enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, - Suite_kind=4}; -struct _mod { - enum _mod_kind kind; - union { - struct { - asdl_seq *body; - } Module; - - struct { - asdl_seq *body; - } Interactive; - - struct { - expr_ty body; - } Expression; - - struct { - asdl_seq *body; - } Suite; - - } v; -}; - -enum _stmt_kind {FunctionDef_kind=1, AsyncFunctionDef_kind=2, ClassDef_kind=3, - Return_kind=4, Delete_kind=5, Assign_kind=6, - AugAssign_kind=7, For_kind=8, AsyncFor_kind=9, While_kind=10, - If_kind=11, With_kind=12, AsyncWith_kind=13, Raise_kind=14, - Try_kind=15, Assert_kind=16, Import_kind=17, - ImportFrom_kind=18, Global_kind=19, Nonlocal_kind=20, - Expr_kind=21, Pass_kind=22, Break_kind=23, Continue_kind=24}; -struct _stmt { - enum _stmt_kind kind; - union { - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - } FunctionDef; - - struct { - identifier name; - arguments_ty args; - asdl_seq *body; - asdl_seq *decorator_list; - expr_ty returns; - } AsyncFunctionDef; - - struct { - identifier name; - asdl_seq *bases; - asdl_seq *keywords; - asdl_seq *body; - asdl_seq *decorator_list; - } ClassDef; - - struct { - expr_ty value; - } Return; - - struct { - asdl_seq *targets; - } Delete; - - struct { - asdl_seq *targets; - expr_ty value; - } Assign; - - struct { - expr_ty target; - operator_ty op; - expr_ty value; - } AugAssign; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - } For; - - struct { - expr_ty target; - expr_ty iter; - asdl_seq *body; - asdl_seq *orelse; - } AsyncFor; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } While; - - struct { - expr_ty test; - asdl_seq *body; - asdl_seq *orelse; - } If; - - struct { - asdl_seq *items; - asdl_seq *body; - } With; - - struct { - asdl_seq *items; - asdl_seq *body; - } AsyncWith; - - struct { - expr_ty exc; - expr_ty cause; - } Raise; - - struct { - asdl_seq *body; - asdl_seq *handlers; - asdl_seq *orelse; - asdl_seq *finalbody; - } Try; - - struct { - expr_ty test; - expr_ty msg; - } Assert; - - struct { - asdl_seq *names; - } Import; - - struct { - identifier module; - asdl_seq *names; - int level; - } ImportFrom; - - struct { - asdl_seq *names; - } Global; - - struct { - asdl_seq *names; - } Nonlocal; - - struct { - expr_ty value; - } Expr; - - } v; - int lineno; - int col_offset; -}; - -enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, - IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, - SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, - Await_kind=12, Yield_kind=13, YieldFrom_kind=14, - Compare_kind=15, Call_kind=16, Num_kind=17, Str_kind=18, - Bytes_kind=19, NameConstant_kind=20, Ellipsis_kind=21, - Attribute_kind=22, Subscript_kind=23, Starred_kind=24, - Name_kind=25, List_kind=26, Tuple_kind=27}; -struct _expr { - enum _expr_kind kind; - union { - struct { - boolop_ty op; - asdl_seq *values; - } BoolOp; - - struct { - expr_ty left; - operator_ty op; - expr_ty right; - } BinOp; - - struct { - unaryop_ty op; - expr_ty operand; - } UnaryOp; - - struct { - arguments_ty args; - expr_ty body; - } Lambda; - - struct { - expr_ty test; - expr_ty body; - expr_ty orelse; - } IfExp; - - struct { - asdl_seq *keys; - asdl_seq *values; - } Dict; - - struct { - asdl_seq *elts; - } Set; - - struct { - expr_ty elt; - asdl_seq *generators; - } ListComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } SetComp; - - struct { - expr_ty key; - expr_ty value; - asdl_seq *generators; - } DictComp; - - struct { - expr_ty elt; - asdl_seq *generators; - } GeneratorExp; - - struct { - expr_ty value; - } Await; - - struct { - expr_ty value; - } Yield; - - struct { - expr_ty value; - } YieldFrom; - - struct { - expr_ty left; - asdl_int_seq *ops; - asdl_seq *comparators; - } Compare; - - struct { - expr_ty func; - asdl_seq *args; - asdl_seq *keywords; - } Call; - - struct { - object n; - } Num; - - struct { - string s; - } Str; - - struct { - bytes s; - } Bytes; - - struct { - singleton value; - } NameConstant; - - struct { - expr_ty value; - identifier attr; - expr_context_ty ctx; - } Attribute; - - struct { - expr_ty value; - slice_ty slice; - expr_context_ty ctx; - } Subscript; - - struct { - expr_ty value; - expr_context_ty ctx; - } Starred; - - struct { - identifier id; - expr_context_ty ctx; - } Name; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } List; - - struct { - asdl_seq *elts; - expr_context_ty ctx; - } Tuple; - - } v; - int lineno; - int col_offset; -}; - -enum _slice_kind {Slice_kind=1, ExtSlice_kind=2, Index_kind=3}; -struct _slice { - enum _slice_kind kind; - union { - struct { - expr_ty lower; - expr_ty upper; - expr_ty step; - } Slice; - - struct { - asdl_seq *dims; - } ExtSlice; - - struct { - expr_ty value; - } Index; - - } v; -}; - -struct _comprehension { - expr_ty target; - expr_ty iter; - asdl_seq *ifs; -}; - -enum _excepthandler_kind {ExceptHandler_kind=1}; -struct _excepthandler { - enum _excepthandler_kind kind; - union { - struct { - expr_ty type; - identifier name; - asdl_seq *body; - } ExceptHandler; - - } v; - int lineno; - int col_offset; -}; - -struct _arguments { - asdl_seq *args; - arg_ty vararg; - asdl_seq *kwonlyargs; - asdl_seq *kw_defaults; - arg_ty kwarg; - asdl_seq *defaults; -}; - -struct _arg { - identifier arg; - expr_ty annotation; - int lineno; - int col_offset; -}; - -struct _keyword { - identifier arg; - expr_ty value; -}; - -struct _alias { - identifier name; - identifier asname; -}; - -struct _withitem { - expr_ty context_expr; - expr_ty optional_vars; -}; - - -#define Module(a0, a1) _Py_Module(a0, a1) -mod_ty _Py_Module(asdl_seq * body, PyArena *arena); -#define Interactive(a0, a1) _Py_Interactive(a0, a1) -mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); -#define Expression(a0, a1) _Py_Expression(a0, a1) -mod_ty _Py_Expression(expr_ty body, PyArena *arena); -#define Suite(a0, a1) _Py_Suite(a0, a1) -mod_ty _Py_Suite(asdl_seq * body, PyArena *arena); -#define FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, - asdl_seq * decorator_list, expr_ty returns, int lineno, - int col_offset, PyArena *arena); -#define AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq * - body, asdl_seq * decorator_list, expr_ty returns, - int lineno, int col_offset, PyArena *arena); -#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) -stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, - asdl_seq * body, asdl_seq * decorator_list, int lineno, - int col_offset, PyArena *arena); -#define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) -stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); -#define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3) -stmt_ty _Py_Delete(asdl_seq * targets, int lineno, int col_offset, PyArena - *arena); -#define Assign(a0, a1, a2, a3, a4) _Py_Assign(a0, a1, a2, a3, a4) -stmt_ty _Py_Assign(asdl_seq * targets, expr_ty value, int lineno, int - col_offset, PyArena *arena); -#define AugAssign(a0, a1, a2, a3, a4, a5) _Py_AugAssign(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_AugAssign(expr_ty target, operator_ty op, expr_ty value, int - lineno, int col_offset, PyArena *arena); -#define For(a0, a1, a2, a3, a4, a5, a6) _Py_For(a0, a1, a2, a3, a4, a5, a6) -stmt_ty _Py_For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * - orelse, int lineno, int col_offset, PyArena *arena); -#define AsyncFor(a0, a1, a2, a3, a4, a5, a6) _Py_AsyncFor(a0, a1, a2, a3, a4, a5, a6) -stmt_ty _Py_AsyncFor(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * - orelse, int lineno, int col_offset, PyArena *arena); -#define While(a0, a1, a2, a3, a4, a5) _Py_While(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, - int col_offset, PyArena *arena); -#define If(a0, a1, a2, a3, a4, a5) _Py_If(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, - int col_offset, PyArena *arena); -#define With(a0, a1, a2, a3, a4) _Py_With(a0, a1, a2, a3, a4) -stmt_ty _Py_With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, - PyArena *arena); -#define AsyncWith(a0, a1, a2, a3, a4) _Py_AsyncWith(a0, a1, a2, a3, a4) -stmt_ty _Py_AsyncWith(asdl_seq * items, asdl_seq * body, int lineno, int - col_offset, PyArena *arena); -#define Raise(a0, a1, a2, a3, a4) _Py_Raise(a0, a1, a2, a3, a4) -stmt_ty _Py_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, - PyArena *arena); -#define Try(a0, a1, a2, a3, a4, a5, a6) _Py_Try(a0, a1, a2, a3, a4, a5, a6) -stmt_ty _Py_Try(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, - asdl_seq * finalbody, int lineno, int col_offset, PyArena - *arena); -#define Assert(a0, a1, a2, a3, a4) _Py_Assert(a0, a1, a2, a3, a4) -stmt_ty _Py_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, - PyArena *arena); -#define Import(a0, a1, a2, a3) _Py_Import(a0, a1, a2, a3) -stmt_ty _Py_Import(asdl_seq * names, int lineno, int col_offset, PyArena - *arena); -#define ImportFrom(a0, a1, a2, a3, a4, a5) _Py_ImportFrom(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_ImportFrom(identifier module, asdl_seq * names, int level, int - lineno, int col_offset, PyArena *arena); -#define Global(a0, a1, a2, a3) _Py_Global(a0, a1, a2, a3) -stmt_ty _Py_Global(asdl_seq * names, int lineno, int col_offset, PyArena - *arena); -#define Nonlocal(a0, a1, a2, a3) _Py_Nonlocal(a0, a1, a2, a3) -stmt_ty _Py_Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena - *arena); -#define Expr(a0, a1, a2, a3) _Py_Expr(a0, a1, a2, a3) -stmt_ty _Py_Expr(expr_ty value, int lineno, int col_offset, PyArena *arena); -#define Pass(a0, a1, a2) _Py_Pass(a0, a1, a2) -stmt_ty _Py_Pass(int lineno, int col_offset, PyArena *arena); -#define Break(a0, a1, a2) _Py_Break(a0, a1, a2) -stmt_ty _Py_Break(int lineno, int col_offset, PyArena *arena); -#define Continue(a0, a1, a2) _Py_Continue(a0, a1, a2) -stmt_ty _Py_Continue(int lineno, int col_offset, PyArena *arena); -#define BoolOp(a0, a1, a2, a3, a4) _Py_BoolOp(a0, a1, a2, a3, a4) -expr_ty _Py_BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, - PyArena *arena); -#define BinOp(a0, a1, a2, a3, a4, a5) _Py_BinOp(a0, a1, a2, a3, a4, a5) -expr_ty _Py_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int - col_offset, PyArena *arena); -#define UnaryOp(a0, a1, a2, a3, a4) _Py_UnaryOp(a0, a1, a2, a3, a4) -expr_ty _Py_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, - PyArena *arena); -#define Lambda(a0, a1, a2, a3, a4) _Py_Lambda(a0, a1, a2, a3, a4) -expr_ty _Py_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, - PyArena *arena); -#define IfExp(a0, a1, a2, a3, a4, a5) _Py_IfExp(a0, a1, a2, a3, a4, a5) -expr_ty _Py_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int - col_offset, PyArena *arena); -#define Dict(a0, a1, a2, a3, a4) _Py_Dict(a0, a1, a2, a3, a4) -expr_ty _Py_Dict(asdl_seq * keys, asdl_seq * values, int lineno, int - col_offset, PyArena *arena); -#define Set(a0, a1, a2, a3) _Py_Set(a0, a1, a2, a3) -expr_ty _Py_Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena); -#define ListComp(a0, a1, a2, a3, a4) _Py_ListComp(a0, a1, a2, a3, a4) -expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, PyArena *arena); -#define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4) -expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, PyArena *arena); -#define DictComp(a0, a1, a2, a3, a4, a5) _Py_DictComp(a0, a1, a2, a3, a4, a5) -expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int - lineno, int col_offset, PyArena *arena); -#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4) -expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int - col_offset, PyArena *arena); -#define Await(a0, a1, a2, a3) _Py_Await(a0, a1, a2, a3) -expr_ty _Py_Await(expr_ty value, int lineno, int col_offset, PyArena *arena); -#define Yield(a0, a1, a2, a3) _Py_Yield(a0, a1, a2, a3) -expr_ty _Py_Yield(expr_ty value, int lineno, int col_offset, PyArena *arena); -#define YieldFrom(a0, a1, a2, a3) _Py_YieldFrom(a0, a1, a2, a3) -expr_ty _Py_YieldFrom(expr_ty value, int lineno, int col_offset, PyArena - *arena); -#define Compare(a0, a1, a2, a3, a4, a5) _Py_Compare(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, - int lineno, int col_offset, PyArena *arena); -#define Call(a0, a1, a2, a3, a4, a5) _Py_Call(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, int - lineno, int col_offset, PyArena *arena); -#define Num(a0, a1, a2, a3) _Py_Num(a0, a1, a2, a3) -expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena); -#define Str(a0, a1, a2, a3) _Py_Str(a0, a1, a2, a3) -expr_ty _Py_Str(string s, int lineno, int col_offset, PyArena *arena); -#define Bytes(a0, a1, a2, a3) _Py_Bytes(a0, a1, a2, a3) -expr_ty _Py_Bytes(bytes s, int lineno, int col_offset, PyArena *arena); -#define NameConstant(a0, a1, a2, a3) _Py_NameConstant(a0, a1, a2, a3) -expr_ty _Py_NameConstant(singleton value, int lineno, int col_offset, PyArena - *arena); -#define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2) -expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena); -#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int - lineno, int col_offset, PyArena *arena); -#define Subscript(a0, a1, a2, a3, a4, a5) _Py_Subscript(a0, a1, a2, a3, a4, a5) -expr_ty _Py_Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int - lineno, int col_offset, PyArena *arena); -#define Starred(a0, a1, a2, a3, a4) _Py_Starred(a0, a1, a2, a3, a4) -expr_ty _Py_Starred(expr_ty value, expr_context_ty ctx, int lineno, int - col_offset, PyArena *arena); -#define Name(a0, a1, a2, a3, a4) _Py_Name(a0, a1, a2, a3, a4) -expr_ty _Py_Name(identifier id, expr_context_ty ctx, int lineno, int - col_offset, PyArena *arena); -#define List(a0, a1, a2, a3, a4) _Py_List(a0, a1, a2, a3, a4) -expr_ty _Py_List(asdl_seq * elts, expr_context_ty ctx, int lineno, int - col_offset, PyArena *arena); -#define Tuple(a0, a1, a2, a3, a4) _Py_Tuple(a0, a1, a2, a3, a4) -expr_ty _Py_Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int - col_offset, PyArena *arena); -#define Slice(a0, a1, a2, a3) _Py_Slice(a0, a1, a2, a3) -slice_ty _Py_Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena); -#define ExtSlice(a0, a1) _Py_ExtSlice(a0, a1) -slice_ty _Py_ExtSlice(asdl_seq * dims, PyArena *arena); -#define Index(a0, a1) _Py_Index(a0, a1) -slice_ty _Py_Index(expr_ty value, PyArena *arena); -#define comprehension(a0, a1, a2, a3) _Py_comprehension(a0, a1, a2, a3) -comprehension_ty _Py_comprehension(expr_ty target, expr_ty iter, asdl_seq * - ifs, PyArena *arena); -#define ExceptHandler(a0, a1, a2, a3, a4, a5) _Py_ExceptHandler(a0, a1, a2, a3, a4, a5) -excepthandler_ty _Py_ExceptHandler(expr_ty type, identifier name, asdl_seq * - body, int lineno, int col_offset, PyArena - *arena); -#define arguments(a0, a1, a2, a3, a4, a5, a6) _Py_arguments(a0, a1, a2, a3, a4, a5, a6) -arguments_ty _Py_arguments(asdl_seq * args, arg_ty vararg, asdl_seq * - kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, - asdl_seq * defaults, PyArena *arena); -#define arg(a0, a1, a2, a3, a4) _Py_arg(a0, a1, a2, a3, a4) -arg_ty _Py_arg(identifier arg, expr_ty annotation, int lineno, int col_offset, - PyArena *arena); -#define keyword(a0, a1, a2) _Py_keyword(a0, a1, a2) -keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); -#define alias(a0, a1, a2) _Py_alias(a0, a1, a2) -alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); -#define withitem(a0, a1, a2) _Py_withitem(a0, a1, a2) -withitem_ty _Py_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena - *arena); - -PyObject* PyAST_mod2obj(mod_ty t); -mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode); -int PyAST_Check(PyObject* obj); +/* File automatically generated by Parser/asdl_c.py. */ + +#include "asdl.h" + +typedef struct _mod *mod_ty; + +typedef struct _stmt *stmt_ty; + +typedef struct _expr *expr_ty; + +typedef enum _expr_context { Load=1, Store=2, Del=3, AugLoad=4, AugStore=5, + Param=6 } expr_context_ty; + +typedef struct _slice *slice_ty; + +typedef enum _boolop { And=1, Or=2 } boolop_ty; + +typedef enum _operator { Add=1, Sub=2, Mult=3, MatMult=4, Div=5, Mod=6, Pow=7, + LShift=8, RShift=9, BitOr=10, BitXor=11, BitAnd=12, + FloorDiv=13 } operator_ty; + +typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty; + +typedef enum _cmpop { Eq=1, NotEq=2, Lt=3, LtE=4, Gt=5, GtE=6, Is=7, IsNot=8, + In=9, NotIn=10 } cmpop_ty; + +typedef struct _comprehension *comprehension_ty; + +typedef struct _excepthandler *excepthandler_ty; + +typedef struct _arguments *arguments_ty; + +typedef struct _arg *arg_ty; + +typedef struct _keyword *keyword_ty; + +typedef struct _alias *alias_ty; + +typedef struct _withitem *withitem_ty; + + +enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, + Suite_kind=4}; +struct _mod { + enum _mod_kind kind; + union { + struct { + asdl_seq *body; + } Module; + + struct { + asdl_seq *body; + } Interactive; + + struct { + expr_ty body; + } Expression; + + struct { + asdl_seq *body; + } Suite; + + } v; +}; + +enum _stmt_kind {FunctionDef_kind=1, AsyncFunctionDef_kind=2, ClassDef_kind=3, + Return_kind=4, Delete_kind=5, Assign_kind=6, + AugAssign_kind=7, For_kind=8, AsyncFor_kind=9, While_kind=10, + If_kind=11, With_kind=12, AsyncWith_kind=13, Raise_kind=14, + Try_kind=15, Assert_kind=16, Import_kind=17, + ImportFrom_kind=18, Global_kind=19, Nonlocal_kind=20, + Expr_kind=21, Pass_kind=22, Break_kind=23, Continue_kind=24}; +struct _stmt { + enum _stmt_kind kind; + union { + struct { + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorator_list; + expr_ty returns; + } FunctionDef; + + struct { + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorator_list; + expr_ty returns; + } AsyncFunctionDef; + + struct { + identifier name; + asdl_seq *bases; + asdl_seq *keywords; + asdl_seq *body; + asdl_seq *decorator_list; + } ClassDef; + + struct { + expr_ty value; + } Return; + + struct { + asdl_seq *targets; + } Delete; + + struct { + asdl_seq *targets; + expr_ty value; + } Assign; + + struct { + expr_ty target; + operator_ty op; + expr_ty value; + } AugAssign; + + struct { + expr_ty target; + expr_ty iter; + asdl_seq *body; + asdl_seq *orelse; + } For; + + struct { + expr_ty target; + expr_ty iter; + asdl_seq *body; + asdl_seq *orelse; + } AsyncFor; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } While; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } If; + + struct { + asdl_seq *items; + asdl_seq *body; + } With; + + struct { + asdl_seq *items; + asdl_seq *body; + } AsyncWith; + + struct { + expr_ty exc; + expr_ty cause; + } Raise; + + struct { + asdl_seq *body; + asdl_seq *handlers; + asdl_seq *orelse; + asdl_seq *finalbody; + } Try; + + struct { + expr_ty test; + expr_ty msg; + } Assert; + + struct { + asdl_seq *names; + } Import; + + struct { + identifier module; + asdl_seq *names; + int level; + } ImportFrom; + + struct { + asdl_seq *names; + } Global; + + struct { + asdl_seq *names; + } Nonlocal; + + struct { + expr_ty value; + } Expr; + + } v; + int lineno; + int col_offset; +}; + +enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, + IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, + SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, + Await_kind=12, Yield_kind=13, YieldFrom_kind=14, + Compare_kind=15, Call_kind=16, Num_kind=17, Str_kind=18, + Bytes_kind=19, NameConstant_kind=20, Ellipsis_kind=21, + Attribute_kind=22, Subscript_kind=23, Starred_kind=24, + Name_kind=25, List_kind=26, Tuple_kind=27}; +struct _expr { + enum _expr_kind kind; + union { + struct { + boolop_ty op; + asdl_seq *values; + } BoolOp; + + struct { + expr_ty left; + operator_ty op; + expr_ty right; + } BinOp; + + struct { + unaryop_ty op; + expr_ty operand; + } UnaryOp; + + struct { + arguments_ty args; + expr_ty body; + } Lambda; + + struct { + expr_ty test; + expr_ty body; + expr_ty orelse; + } IfExp; + + struct { + asdl_seq *keys; + asdl_seq *values; + } Dict; + + struct { + asdl_seq *elts; + } Set; + + struct { + expr_ty elt; + asdl_seq *generators; + } ListComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } SetComp; + + struct { + expr_ty key; + expr_ty value; + asdl_seq *generators; + } DictComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } GeneratorExp; + + struct { + expr_ty value; + } Await; + + struct { + expr_ty value; + } Yield; + + struct { + expr_ty value; + } YieldFrom; + + struct { + expr_ty left; + asdl_int_seq *ops; + asdl_seq *comparators; + } Compare; + + struct { + expr_ty func; + asdl_seq *args; + asdl_seq *keywords; + } Call; + + struct { + object n; + } Num; + + struct { + string s; + } Str; + + struct { + bytes s; + } Bytes; + + struct { + singleton value; + } NameConstant; + + struct { + expr_ty value; + identifier attr; + expr_context_ty ctx; + } Attribute; + + struct { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + } Subscript; + + struct { + expr_ty value; + expr_context_ty ctx; + } Starred; + + struct { + identifier id; + expr_context_ty ctx; + } Name; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } List; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } Tuple; + + } v; + int lineno; + int col_offset; +}; + +enum _slice_kind {Slice_kind=1, ExtSlice_kind=2, Index_kind=3}; +struct _slice { + enum _slice_kind kind; + union { + struct { + expr_ty lower; + expr_ty upper; + expr_ty step; + } Slice; + + struct { + asdl_seq *dims; + } ExtSlice; + + struct { + expr_ty value; + } Index; + + } v; +}; + +struct _comprehension { + expr_ty target; + expr_ty iter; + asdl_seq *ifs; +}; + +enum _excepthandler_kind {ExceptHandler_kind=1}; +struct _excepthandler { + enum _excepthandler_kind kind; + union { + struct { + expr_ty type; + identifier name; + asdl_seq *body; + } ExceptHandler; + + } v; + int lineno; + int col_offset; +}; + +struct _arguments { + asdl_seq *args; + arg_ty vararg; + asdl_seq *kwonlyargs; + asdl_seq *kw_defaults; + arg_ty kwarg; + asdl_seq *defaults; +}; + +struct _arg { + identifier arg; + expr_ty annotation; + int lineno; + int col_offset; +}; + +struct _keyword { + identifier arg; + expr_ty value; +}; + +struct _alias { + identifier name; + identifier asname; +}; + +struct _withitem { + expr_ty context_expr; + expr_ty optional_vars; +}; + + +#define Module(a0, a1) _Py_Module(a0, a1) +mod_ty _Py_Module(asdl_seq * body, PyArena *arena); +#define Interactive(a0, a1) _Py_Interactive(a0, a1) +mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); +#define Expression(a0, a1) _Py_Expression(a0, a1) +mod_ty _Py_Expression(expr_ty body, PyArena *arena); +#define Suite(a0, a1) _Py_Suite(a0, a1) +mod_ty _Py_Suite(asdl_seq * body, PyArena *arena); +#define FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) +stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, + asdl_seq * decorator_list, expr_ty returns, int lineno, + int col_offset, PyArena *arena); +#define AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_AsyncFunctionDef(a0, a1, a2, a3, a4, a5, a6, a7) +stmt_ty _Py_AsyncFunctionDef(identifier name, arguments_ty args, asdl_seq * + body, asdl_seq * decorator_list, expr_ty returns, + int lineno, int col_offset, PyArena *arena); +#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7) +stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, + asdl_seq * body, asdl_seq * decorator_list, int lineno, + int col_offset, PyArena *arena); +#define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) +stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3) +stmt_ty _Py_Delete(asdl_seq * targets, int lineno, int col_offset, PyArena + *arena); +#define Assign(a0, a1, a2, a3, a4) _Py_Assign(a0, a1, a2, a3, a4) +stmt_ty _Py_Assign(asdl_seq * targets, expr_ty value, int lineno, int + col_offset, PyArena *arena); +#define AugAssign(a0, a1, a2, a3, a4, a5) _Py_AugAssign(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_AugAssign(expr_ty target, operator_ty op, expr_ty value, int + lineno, int col_offset, PyArena *arena); +#define For(a0, a1, a2, a3, a4, a5, a6) _Py_For(a0, a1, a2, a3, a4, a5, a6) +stmt_ty _Py_For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * + orelse, int lineno, int col_offset, PyArena *arena); +#define AsyncFor(a0, a1, a2, a3, a4, a5, a6) _Py_AsyncFor(a0, a1, a2, a3, a4, a5, a6) +stmt_ty _Py_AsyncFor(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * + orelse, int lineno, int col_offset, PyArena *arena); +#define While(a0, a1, a2, a3, a4, a5) _Py_While(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, + int col_offset, PyArena *arena); +#define If(a0, a1, a2, a3, a4, a5) _Py_If(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, + int col_offset, PyArena *arena); +#define With(a0, a1, a2, a3, a4) _Py_With(a0, a1, a2, a3, a4) +stmt_ty _Py_With(asdl_seq * items, asdl_seq * body, int lineno, int col_offset, + PyArena *arena); +#define AsyncWith(a0, a1, a2, a3, a4) _Py_AsyncWith(a0, a1, a2, a3, a4) +stmt_ty _Py_AsyncWith(asdl_seq * items, asdl_seq * body, int lineno, int + col_offset, PyArena *arena); +#define Raise(a0, a1, a2, a3, a4) _Py_Raise(a0, a1, a2, a3, a4) +stmt_ty _Py_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, + PyArena *arena); +#define Try(a0, a1, a2, a3, a4, a5, a6) _Py_Try(a0, a1, a2, a3, a4, a5, a6) +stmt_ty _Py_Try(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, + asdl_seq * finalbody, int lineno, int col_offset, PyArena + *arena); +#define Assert(a0, a1, a2, a3, a4) _Py_Assert(a0, a1, a2, a3, a4) +stmt_ty _Py_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, + PyArena *arena); +#define Import(a0, a1, a2, a3) _Py_Import(a0, a1, a2, a3) +stmt_ty _Py_Import(asdl_seq * names, int lineno, int col_offset, PyArena + *arena); +#define ImportFrom(a0, a1, a2, a3, a4, a5) _Py_ImportFrom(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_ImportFrom(identifier module, asdl_seq * names, int level, int + lineno, int col_offset, PyArena *arena); +#define Global(a0, a1, a2, a3) _Py_Global(a0, a1, a2, a3) +stmt_ty _Py_Global(asdl_seq * names, int lineno, int col_offset, PyArena + *arena); +#define Nonlocal(a0, a1, a2, a3) _Py_Nonlocal(a0, a1, a2, a3) +stmt_ty _Py_Nonlocal(asdl_seq * names, int lineno, int col_offset, PyArena + *arena); +#define Expr(a0, a1, a2, a3) _Py_Expr(a0, a1, a2, a3) +stmt_ty _Py_Expr(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Pass(a0, a1, a2) _Py_Pass(a0, a1, a2) +stmt_ty _Py_Pass(int lineno, int col_offset, PyArena *arena); +#define Break(a0, a1, a2) _Py_Break(a0, a1, a2) +stmt_ty _Py_Break(int lineno, int col_offset, PyArena *arena); +#define Continue(a0, a1, a2) _Py_Continue(a0, a1, a2) +stmt_ty _Py_Continue(int lineno, int col_offset, PyArena *arena); +#define BoolOp(a0, a1, a2, a3, a4) _Py_BoolOp(a0, a1, a2, a3, a4) +expr_ty _Py_BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, + PyArena *arena); +#define BinOp(a0, a1, a2, a3, a4, a5) _Py_BinOp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int + col_offset, PyArena *arena); +#define UnaryOp(a0, a1, a2, a3, a4) _Py_UnaryOp(a0, a1, a2, a3, a4) +expr_ty _Py_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, + PyArena *arena); +#define Lambda(a0, a1, a2, a3, a4) _Py_Lambda(a0, a1, a2, a3, a4) +expr_ty _Py_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, + PyArena *arena); +#define IfExp(a0, a1, a2, a3, a4, a5) _Py_IfExp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int + col_offset, PyArena *arena); +#define Dict(a0, a1, a2, a3, a4) _Py_Dict(a0, a1, a2, a3, a4) +expr_ty _Py_Dict(asdl_seq * keys, asdl_seq * values, int lineno, int + col_offset, PyArena *arena); +#define Set(a0, a1, a2, a3) _Py_Set(a0, a1, a2, a3) +expr_ty _Py_Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena); +#define ListComp(a0, a1, a2, a3, a4) _Py_ListComp(a0, a1, a2, a3, a4) +expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena); +#define SetComp(a0, a1, a2, a3, a4) _Py_SetComp(a0, a1, a2, a3, a4) +expr_ty _Py_SetComp(expr_ty elt, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena); +#define DictComp(a0, a1, a2, a3, a4, a5) _Py_DictComp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_DictComp(expr_ty key, expr_ty value, asdl_seq * generators, int + lineno, int col_offset, PyArena *arena); +#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4) +expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena); +#define Await(a0, a1, a2, a3) _Py_Await(a0, a1, a2, a3) +expr_ty _Py_Await(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Yield(a0, a1, a2, a3) _Py_Yield(a0, a1, a2, a3) +expr_ty _Py_Yield(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define YieldFrom(a0, a1, a2, a3) _Py_YieldFrom(a0, a1, a2, a3) +expr_ty _Py_YieldFrom(expr_ty value, int lineno, int col_offset, PyArena + *arena); +#define Compare(a0, a1, a2, a3, a4, a5) _Py_Compare(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, + int lineno, int col_offset, PyArena *arena); +#define Call(a0, a1, a2, a3, a4, a5) _Py_Call(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, int + lineno, int col_offset, PyArena *arena); +#define Num(a0, a1, a2, a3) _Py_Num(a0, a1, a2, a3) +expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena); +#define Str(a0, a1, a2, a3) _Py_Str(a0, a1, a2, a3) +expr_ty _Py_Str(string s, int lineno, int col_offset, PyArena *arena); +#define Bytes(a0, a1, a2, a3) _Py_Bytes(a0, a1, a2, a3) +expr_ty _Py_Bytes(bytes s, int lineno, int col_offset, PyArena *arena); +#define NameConstant(a0, a1, a2, a3) _Py_NameConstant(a0, a1, a2, a3) +expr_ty _Py_NameConstant(singleton value, int lineno, int col_offset, PyArena + *arena); +#define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2) +expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena); +#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int + lineno, int col_offset, PyArena *arena); +#define Subscript(a0, a1, a2, a3, a4, a5) _Py_Subscript(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int + lineno, int col_offset, PyArena *arena); +#define Starred(a0, a1, a2, a3, a4) _Py_Starred(a0, a1, a2, a3, a4) +expr_ty _Py_Starred(expr_ty value, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define Name(a0, a1, a2, a3, a4) _Py_Name(a0, a1, a2, a3, a4) +expr_ty _Py_Name(identifier id, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define List(a0, a1, a2, a3, a4) _Py_List(a0, a1, a2, a3, a4) +expr_ty _Py_List(asdl_seq * elts, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define Tuple(a0, a1, a2, a3, a4) _Py_Tuple(a0, a1, a2, a3, a4) +expr_ty _Py_Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define Slice(a0, a1, a2, a3) _Py_Slice(a0, a1, a2, a3) +slice_ty _Py_Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena); +#define ExtSlice(a0, a1) _Py_ExtSlice(a0, a1) +slice_ty _Py_ExtSlice(asdl_seq * dims, PyArena *arena); +#define Index(a0, a1) _Py_Index(a0, a1) +slice_ty _Py_Index(expr_ty value, PyArena *arena); +#define comprehension(a0, a1, a2, a3) _Py_comprehension(a0, a1, a2, a3) +comprehension_ty _Py_comprehension(expr_ty target, expr_ty iter, asdl_seq * + ifs, PyArena *arena); +#define ExceptHandler(a0, a1, a2, a3, a4, a5) _Py_ExceptHandler(a0, a1, a2, a3, a4, a5) +excepthandler_ty _Py_ExceptHandler(expr_ty type, identifier name, asdl_seq * + body, int lineno, int col_offset, PyArena + *arena); +#define arguments(a0, a1, a2, a3, a4, a5, a6) _Py_arguments(a0, a1, a2, a3, a4, a5, a6) +arguments_ty _Py_arguments(asdl_seq * args, arg_ty vararg, asdl_seq * + kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, + asdl_seq * defaults, PyArena *arena); +#define arg(a0, a1, a2, a3, a4) _Py_arg(a0, a1, a2, a3, a4) +arg_ty _Py_arg(identifier arg, expr_ty annotation, int lineno, int col_offset, + PyArena *arena); +#define keyword(a0, a1, a2) _Py_keyword(a0, a1, a2) +keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); +#define alias(a0, a1, a2) _Py_alias(a0, a1, a2) +alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); +#define withitem(a0, a1, a2) _Py_withitem(a0, a1, a2) +withitem_ty _Py_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena + *arena); + +PyObject* PyAST_mod2obj(mod_ty t); +mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode); +int PyAST_Check(PyObject* obj); diff --git a/libs/nxpy/include/Python.h b/libs/nxpy/include/Python.h index 858dbd1a..22b320b2 100644 --- a/libs/nxpy/include/Python.h +++ b/libs/nxpy/include/Python.h @@ -1,135 +1,135 @@ -#ifndef Py_PYTHON_H -#define Py_PYTHON_H -/* Since this is a "meta-include" file, no #ifdef __cplusplus / extern "C" { */ - -/* Include nearly all Python header files */ - -#include "patchlevel.h" -#include "pyconfig.h" -#include "pymacconfig.h" - -#include - -#ifndef UCHAR_MAX -#error "Something's broken. UCHAR_MAX should be defined in limits.h." -#endif - -#if UCHAR_MAX != 255 -#error "Python's source code assumes C's unsigned char is an 8-bit type." -#endif - -#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE) -#define _SGI_MP_SOURCE -#endif - -#include -#ifndef NULL -# error "Python.h requires that stdio.h define NULL." -#endif - -#include -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -/* For size_t? */ -#ifdef HAVE_STDDEF_H -#include -#endif - -/* CAUTION: Build setups should ensure that NDEBUG is defined on the - * compiler command line when building Python in release mode; else - * assert() calls won't be removed. - */ -#include - -#include "pyport.h" -#include "pymacro.h" - -#include "pyatomic.h" - -/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG. - * PYMALLOC_DEBUG is in error if pymalloc is not in use. - */ -#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG) -#define PYMALLOC_DEBUG -#endif -#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC) -#error "PYMALLOC_DEBUG requires WITH_PYMALLOC" -#endif -#include "pymath.h" -#include "pytime.h" -#include "pymem.h" - -#include "object.h" -#include "objimpl.h" -#include "typeslots.h" -#include "pyhash.h" - -#include "pydebug.h" - -#include "bytearrayobject.h" -#include "bytesobject.h" -#include "unicodeobject.h" -#include "longobject.h" -#include "longintrepr.h" -#include "boolobject.h" -#include "floatobject.h" -#include "complexobject.h" -#include "rangeobject.h" -#include "memoryobject.h" -#include "tupleobject.h" -#include "listobject.h" -#include "dictobject.h" -#include "odictobject.h" -#include "enumobject.h" -#include "setobject.h" -#include "methodobject.h" -#include "moduleobject.h" -#include "funcobject.h" -#include "classobject.h" -#include "fileobject.h" -#include "pycapsule.h" -#include "traceback.h" -#include "sliceobject.h" -#include "cellobject.h" -#include "iterobject.h" -#include "genobject.h" -#include "descrobject.h" -#include "warnings.h" -#include "weakrefobject.h" -#include "structseq.h" -#include "namespaceobject.h" - -#include "codecs.h" -#include "pyerrors.h" - -#include "pystate.h" - -#include "pyarena.h" -#include "modsupport.h" -#include "pythonrun.h" -#include "pylifecycle.h" -#include "ceval.h" -#include "sysmodule.h" -#include "intrcheck.h" -#include "import.h" - -#include "abstract.h" -#include "bltinmodule.h" - -#include "compile.h" -#include "eval.h" - -#include "pyctype.h" -#include "pystrtod.h" -#include "pystrcmp.h" -#include "dtoa.h" -#include "fileutils.h" -#include "pyfpe.h" - -#endif /* !Py_PYTHON_H */ +#ifndef Py_PYTHON_H +#define Py_PYTHON_H +/* Since this is a "meta-include" file, no #ifdef __cplusplus / extern "C" { */ + +/* Include nearly all Python header files */ + +#include "patchlevel.h" +#include "pyconfig.h" +#include "pymacconfig.h" + +#include + +#ifndef UCHAR_MAX +#error "Something's broken. UCHAR_MAX should be defined in limits.h." +#endif + +#if UCHAR_MAX != 255 +#error "Python's source code assumes C's unsigned char is an 8-bit type." +#endif + +#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE) +#define _SGI_MP_SOURCE +#endif + +#include +#ifndef NULL +# error "Python.h requires that stdio.h define NULL." +#endif + +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +/* For size_t? */ +#ifdef HAVE_STDDEF_H +#include +#endif + +/* CAUTION: Build setups should ensure that NDEBUG is defined on the + * compiler command line when building Python in release mode; else + * assert() calls won't be removed. + */ +#include + +#include "pyport.h" +#include "pymacro.h" + +#include "pyatomic.h" + +/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG. + * PYMALLOC_DEBUG is in error if pymalloc is not in use. + */ +#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG) +#define PYMALLOC_DEBUG +#endif +#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC) +#error "PYMALLOC_DEBUG requires WITH_PYMALLOC" +#endif +#include "pymath.h" +#include "pytime.h" +#include "pymem.h" + +#include "object.h" +#include "objimpl.h" +#include "typeslots.h" +#include "pyhash.h" + +#include "pydebug.h" + +#include "bytearrayobject.h" +#include "bytesobject.h" +#include "unicodeobject.h" +#include "longobject.h" +#include "longintrepr.h" +#include "boolobject.h" +#include "floatobject.h" +#include "complexobject.h" +#include "rangeobject.h" +#include "memoryobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "odictobject.h" +#include "enumobject.h" +#include "setobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "funcobject.h" +#include "classobject.h" +#include "fileobject.h" +#include "pycapsule.h" +#include "traceback.h" +#include "sliceobject.h" +#include "cellobject.h" +#include "iterobject.h" +#include "genobject.h" +#include "descrobject.h" +#include "warnings.h" +#include "weakrefobject.h" +#include "structseq.h" +#include "namespaceobject.h" + +#include "codecs.h" +#include "pyerrors.h" + +#include "pystate.h" + +#include "pyarena.h" +#include "modsupport.h" +#include "pythonrun.h" +#include "pylifecycle.h" +#include "ceval.h" +#include "sysmodule.h" +#include "intrcheck.h" +#include "import.h" + +#include "abstract.h" +#include "bltinmodule.h" + +#include "compile.h" +#include "eval.h" + +#include "pyctype.h" +#include "pystrtod.h" +#include "pystrcmp.h" +#include "dtoa.h" +#include "fileutils.h" +#include "pyfpe.h" + +#endif /* !Py_PYTHON_H */ diff --git a/libs/nxpy/include/abstract.h b/libs/nxpy/include/abstract.h index 7dbbb74b..630846b4 100644 --- a/libs/nxpy/include/abstract.h +++ b/libs/nxpy/include/abstract.h @@ -1,1285 +1,1285 @@ -#ifndef Py_ABSTRACTOBJECT_H -#define Py_ABSTRACTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef PY_SSIZE_T_CLEAN -#define PyObject_CallFunction _PyObject_CallFunction_SizeT -#define PyObject_CallMethod _PyObject_CallMethod_SizeT -#define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT -#endif - -/* Abstract Object Interface (many thanks to Jim Fulton) */ - -/* - PROPOSAL: A Generic Python Object Interface for Python C Modules - -Problem - - Python modules written in C that must access Python objects must do - so through routines whose interfaces are described by a set of - include files. Unfortunately, these routines vary according to the - object accessed. To use these routines, the C programmer must check - the type of the object being used and must call a routine based on - the object type. For example, to access an element of a sequence, - the programmer must determine whether the sequence is a list or a - tuple: - - if(is_tupleobject(o)) - e=gettupleitem(o,i) - else if(is_listitem(o)) - e=getlistitem(o,i) - - If the programmer wants to get an item from another type of object - that provides sequence behavior, there is no clear way to do it - correctly. - - The persistent programmer may peruse object.h and find that the - _typeobject structure provides a means of invoking up to (currently - about) 41 special operators. So, for example, a routine can get an - item from any object that provides sequence behavior. However, to - use this mechanism, the programmer must make their code dependent on - the current Python implementation. - - Also, certain semantics, especially memory management semantics, may - differ by the type of object being used. Unfortunately, these - semantics are not clearly described in the current include files. - An abstract interface providing more consistent semantics is needed. - -Proposal - - I propose the creation of a standard interface (with an associated - library of routines and/or macros) for generically obtaining the - services of Python objects. This proposal can be viewed as one - components of a Python C interface consisting of several components. - - From the viewpoint of C access to Python services, we have (as - suggested by Guido in off-line discussions): - - - "Very high level layer": two or three functions that let you exec or - eval arbitrary Python code given as a string in a module whose name is - given, passing C values in and getting C values out using - mkvalue/getargs style format strings. This does not require the user - to declare any variables of type "PyObject *". This should be enough - to write a simple application that gets Python code from the user, - execs it, and returns the output or errors. (Error handling must also - be part of this API.) - - - "Abstract objects layer": which is the subject of this proposal. - It has many functions operating on objects, and lest you do many - things from C that you can also write in Python, without going - through the Python parser. - - - "Concrete objects layer": This is the public type-dependent - interface provided by the standard built-in types, such as floats, - strings, and lists. This interface exists and is currently - documented by the collection of include files provided with the - Python distributions. - - From the point of view of Python accessing services provided by C - modules: - - - "Python module interface": this interface consist of the basic - routines used to define modules and their members. Most of the - current extensions-writing guide deals with this interface. - - - "Built-in object interface": this is the interface that a new - built-in type must provide and the mechanisms and rules that a - developer of a new built-in type must use and follow. - - This proposal is a "first-cut" that is intended to spur - discussion. See especially the lists of notes. - - The Python C object interface will provide four protocols: object, - numeric, sequence, and mapping. Each protocol consists of a - collection of related operations. If an operation that is not - provided by a particular type is invoked, then a standard exception, - NotImplementedError is raised with an operation name as an argument. - In addition, for convenience this interface defines a set of - constructors for building objects of built-in types. This is needed - so new objects can be returned from C functions that otherwise treat - objects generically. - -Memory Management - - For all of the functions described in this proposal, if a function - retains a reference to a Python object passed as an argument, then the - function will increase the reference count of the object. It is - unnecessary for the caller to increase the reference count of an - argument in anticipation of the object's retention. - - All Python objects returned from functions should be treated as new - objects. Functions that return objects assume that the caller will - retain a reference and the reference count of the object has already - been incremented to account for this fact. A caller that does not - retain a reference to an object that is returned from a function - must decrement the reference count of the object (using - DECREF(object)) to prevent memory leaks. - - Note that the behavior mentioned here is different from the current - behavior for some objects (e.g. lists and tuples) when certain - type-specific routines are called directly (e.g. setlistitem). The - proposed abstraction layer will provide a consistent memory - management interface, correcting for inconsistent behavior for some - built-in types. - -Protocols - -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ - -/* Object Protocol: */ - - /* Implemented elsewhere: - - int PyObject_Print(PyObject *o, FILE *fp, int flags); - - Print an object, o, on file, fp. Returns -1 on - error. The flags argument is used to enable certain printing - options. The only option currently supported is Py_Print_RAW. - - (What should be said about Py_Print_RAW?) - - */ - - /* Implemented elsewhere: - - int PyObject_HasAttrString(PyObject *o, const char *attr_name); - - Returns 1 if o has the attribute attr_name, and 0 otherwise. - This is equivalent to the Python expression: - hasattr(o,attr_name). - - This function always succeeds. - - */ - - /* Implemented elsewhere: - - PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name); - - Retrieve an attributed named attr_name form object o. - Returns the attribute value on success, or NULL on failure. - This is the equivalent of the Python expression: o.attr_name. - - */ - - /* Implemented elsewhere: - - int PyObject_HasAttr(PyObject *o, PyObject *attr_name); - - Returns 1 if o has the attribute attr_name, and 0 otherwise. - This is equivalent to the Python expression: - hasattr(o,attr_name). - - This function always succeeds. - - */ - - /* Implemented elsewhere: - - PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name); - - Retrieve an attributed named attr_name form object o. - Returns the attribute value on success, or NULL on failure. - This is the equivalent of the Python expression: o.attr_name. - - */ - - - /* Implemented elsewhere: - - int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v); - - Set the value of the attribute named attr_name, for object o, - to the value v. Raise an exception and return -1 on failure; return 0 on - success. This is the equivalent of the Python statement o.attr_name=v. - - */ - - /* Implemented elsewhere: - - int PyObject_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v); - - Set the value of the attribute named attr_name, for object o, - to the value v. Raise an exception and return -1 on failure; return 0 on - success. This is the equivalent of the Python statement o.attr_name=v. - - */ - - /* implemented as a macro: - - int PyObject_DelAttrString(PyObject *o, const char *attr_name); - - Delete attribute named attr_name, for object o. Returns - -1 on failure. This is the equivalent of the Python - statement: del o.attr_name. - - */ -#define PyObject_DelAttrString(O,A) PyObject_SetAttrString((O),(A),NULL) - - /* implemented as a macro: - - int PyObject_DelAttr(PyObject *o, PyObject *attr_name); - - Delete attribute named attr_name, for object o. Returns -1 - on failure. This is the equivalent of the Python - statement: del o.attr_name. - - */ -#define PyObject_DelAttr(O,A) PyObject_SetAttr((O),(A),NULL) - - /* Implemented elsewhere: - - PyObject *PyObject_Repr(PyObject *o); - - Compute the string representation of object, o. Returns the - string representation on success, NULL on failure. This is - the equivalent of the Python expression: repr(o). - - Called by the repr() built-in function. - - */ - - /* Implemented elsewhere: - - PyObject *PyObject_Str(PyObject *o); - - Compute the string representation of object, o. Returns the - string representation on success, NULL on failure. This is - the equivalent of the Python expression: str(o).) - - Called by the str() and print() built-in functions. - - */ - - /* Declared elsewhere - - PyAPI_FUNC(int) PyCallable_Check(PyObject *o); - - Determine if the object, o, is callable. Return 1 if the - object is callable and 0 otherwise. - - This function always succeeds. - */ - - PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, - PyObject *args, PyObject *kw); - - /* - Call a callable Python object, callable_object, with - arguments and keywords arguments. The 'args' argument can not be - NULL, but the 'kw' argument can be NULL. - */ - -#ifndef Py_LIMITED_API - PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, - PyObject *result, - const char *where); -#endif - - PyAPI_FUNC(PyObject *) PyObject_CallObject(PyObject *callable_object, - PyObject *args); - - /* - Call a callable Python object, callable_object, with - arguments given by the tuple, args. If no arguments are - needed, then args may be NULL. Returns the result of the - call on success, or NULL on failure. This is the equivalent - of the Python expression: o(*args). - */ - - PyAPI_FUNC(PyObject *) PyObject_CallFunction(PyObject *callable_object, - const char *format, ...); - - /* - Call a callable Python object, callable_object, with a - variable number of C arguments. The C arguments are described - using a mkvalue-style format string. The format may be NULL, - indicating that no arguments are provided. Returns the - result of the call on success, or NULL on failure. This is - the equivalent of the Python expression: o(*args). - */ - - - PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *o, - const char *method, - const char *format, ...); - - /* - Call the method named m of object o with a variable number of - C arguments. The C arguments are described by a mkvalue - format string. The format may be NULL, indicating that no - arguments are provided. Returns the result of the call on - success, or NULL on failure. This is the equivalent of the - Python expression: o.method(args). - */ - - PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *o, - _Py_Identifier *method, - const char *format, ...); - - /* - Like PyObject_CallMethod, but expect a _Py_Identifier* as the - method name. - */ - - PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, - const char *format, - ...); - PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *o, - const char *name, - const char *format, - ...); - PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *o, - _Py_Identifier *name, - const char *format, - ...); - - PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable, - ...); - - /* - Call a callable Python object, callable_object, with a - variable number of C arguments. The C arguments are provided - as PyObject * values, terminated by a NULL. Returns the - result of the call on success, or NULL on failure. This is - the equivalent of the Python expression: o(*args). - */ - - - PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs(PyObject *o, - PyObject *method, ...); - PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs(PyObject *o, - struct _Py_Identifier *method, - ...); - - /* - Call the method named m of object o with a variable number of - C arguments. The C arguments are provided as PyObject * - values, terminated by NULL. Returns the result of the call - on success, or NULL on failure. This is the equivalent of - the Python expression: o.method(args). - */ - - - /* Implemented elsewhere: - - long PyObject_Hash(PyObject *o); - - Compute and return the hash, hash_value, of an object, o. On - failure, return -1. This is the equivalent of the Python - expression: hash(o). - */ - - - /* Implemented elsewhere: - - int PyObject_IsTrue(PyObject *o); - - Returns 1 if the object, o, is considered to be true, 0 if o is - considered to be false and -1 on failure. This is equivalent to the - Python expression: not not o - */ - - /* Implemented elsewhere: - - int PyObject_Not(PyObject *o); - - Returns 0 if the object, o, is considered to be true, 1 if o is - considered to be false and -1 on failure. This is equivalent to the - Python expression: not o - */ - - PyAPI_FUNC(PyObject *) PyObject_Type(PyObject *o); - - /* - On success, returns a type object corresponding to the object - type of object o. On failure, returns NULL. This is - equivalent to the Python expression: type(o). - */ - - PyAPI_FUNC(Py_ssize_t) PyObject_Size(PyObject *o); - - /* - Return the size of object o. If the object, o, provides - both sequence and mapping protocols, the sequence size is - returned. On error, -1 is returned. This is the equivalent - to the Python expression: len(o). - */ - - /* For DLL compatibility */ -#undef PyObject_Length - PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o); -#define PyObject_Length PyObject_Size - -#ifndef Py_LIMITED_API - PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); - PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); -#endif - - /* - Guess the size of object o using len(o) or o.__length_hint__(). - If neither of those return a non-negative value, then return the - default value. If one of the calls fails, this function returns -1. - */ - - PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); - - /* - Return element of o corresponding to the object, key, or NULL - on failure. This is the equivalent of the Python expression: - o[key]. - */ - - PyAPI_FUNC(int) PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v); - - /* - Map the object key to the value v. Raise an exception and return -1 - on failure; return 0 on success. This is the equivalent of the Python - statement o[key]=v. - */ - - PyAPI_FUNC(int) PyObject_DelItemString(PyObject *o, const char *key); - - /* - Remove the mapping for object, key, from the object *o. - Returns -1 on failure. This is equivalent to - the Python statement: del o[key]. - */ - - PyAPI_FUNC(int) PyObject_DelItem(PyObject *o, PyObject *key); - - /* - Delete the mapping for key from *o. Returns -1 on failure. - This is the equivalent of the Python statement: del o[key]. - */ - - /* old buffer API - FIXME: usage of these should all be replaced in Python itself - but for backwards compatibility we will implement them. - Their usage without a corresponding "unlock" mechanism - may create issues (but they would already be there). */ - - PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj, - const char **buffer, - Py_ssize_t *buffer_len); - - /* - Takes an arbitrary object which must support the (character, - single segment) buffer interface and returns a pointer to a - read-only memory location useable as character based input - for subsequent processing. - - 0 is returned on success. buffer and buffer_len are only - set in case no error occurs. Otherwise, -1 is returned and - an exception set. - */ - - PyAPI_FUNC(int) PyObject_CheckReadBuffer(PyObject *obj); - - /* - Checks whether an arbitrary object supports the (character, - single segment) buffer interface. Returns 1 on success, 0 - on failure. - */ - - PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *obj, - const void **buffer, - Py_ssize_t *buffer_len); - - /* - Same as PyObject_AsCharBuffer() except that this API expects - (readable, single segment) buffer interface and returns a - pointer to a read-only memory location which can contain - arbitrary data. - - 0 is returned on success. buffer and buffer_len are only - set in case no error occurs. Otherwise, -1 is returned and - an exception set. - */ - - PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj, - void **buffer, - Py_ssize_t *buffer_len); - - /* - Takes an arbitrary object which must support the (writable, - single segment) buffer interface and returns a pointer to a - writable memory location in buffer of size buffer_len. - - 0 is returned on success. buffer and buffer_len are only - set in case no error occurs. Otherwise, -1 is returned and - an exception set. - */ - - /* new buffer API */ - -#ifndef Py_LIMITED_API -#define PyObject_CheckBuffer(obj) \ - (((obj)->ob_type->tp_as_buffer != NULL) && \ - ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL)) - - /* Return 1 if the getbuffer function is available, otherwise - return 0 */ - - PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, - int flags); - - /* This is a C-API version of the getbuffer function call. It checks - to make sure object has the required function pointer and issues the - call. Returns -1 and raises an error on failure and returns 0 on - success - */ - - - PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); - - /* Get the memory area pointed to by the indices for the buffer given. - Note that view->ndim is the assumed size of indices - */ - - PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *); - - /* Return the implied itemsize of the data-format area from a - struct-style description */ - - - - /* Implementation in memoryobject.c */ - PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, - Py_ssize_t len, char order); - - PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, - Py_ssize_t len, char order); - - - /* Copy len bytes of data from the contiguous chunk of memory - pointed to by buf into the buffer exported by obj. Return - 0 on success and return -1 and raise a PyBuffer_Error on - error (i.e. the object does not have a buffer interface or - it is not working). - - If fort is 'F', then if the object is multi-dimensional, - then the data will be copied into the array in - Fortran-style (first dimension varies the fastest). If - fort is 'C', then the data will be copied into the array - in C-style (last dimension varies the fastest). If fort - is 'A', then it does not matter and the copy will be made - in whatever way is more efficient. - - */ - - PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); - - /* Copy the data from the src buffer to the buffer of destination - */ - - PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); - - - PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, - Py_ssize_t *shape, - Py_ssize_t *strides, - int itemsize, - char fort); - - /* Fill the strides array with byte-strides of a contiguous - (Fortran-style if fort is 'F' or C-style otherwise) - array of the given shape with the given number of bytes - per element. - */ - - PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, - Py_ssize_t len, int readonly, - int flags); - - /* Fills in a buffer-info structure correctly for an exporter - that can only share a contiguous chunk of memory of - "unsigned bytes" of the given length. Returns 0 on success - and -1 (with raising an error) on error. - */ - - PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); - - /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*. - */ -#endif /* Py_LIMITED_API */ - - PyAPI_FUNC(PyObject *) PyObject_Format(PyObject* obj, - PyObject *format_spec); - /* - Takes an arbitrary object and returns the result of - calling obj.__format__(format_spec). - */ - -/* Iterators */ - - PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *); - /* Takes an object and returns an iterator for it. - This is typically a new iterator but if the argument - is an iterator, this returns itself. */ - -#define PyIter_Check(obj) \ - ((obj)->ob_type->tp_iternext != NULL && \ - (obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented) - - PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *); - /* Takes an iterator object and calls its tp_iternext slot, - returning the next value. If the iterator is exhausted, - this returns NULL without setting an exception. - NULL with an exception means an error occurred. */ - -/* Number Protocol:*/ - - PyAPI_FUNC(int) PyNumber_Check(PyObject *o); - - /* - Returns 1 if the object, o, provides numeric protocols, and - false otherwise. - - This function always succeeds. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Add(PyObject *o1, PyObject *o2); - - /* - Returns the result of adding o1 and o2, or null on failure. - This is the equivalent of the Python expression: o1+o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Subtract(PyObject *o1, PyObject *o2); - - /* - Returns the result of subtracting o2 from o1, or null on - failure. This is the equivalent of the Python expression: - o1-o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Multiply(PyObject *o1, PyObject *o2); - - /* - Returns the result of multiplying o1 and o2, or null on - failure. This is the equivalent of the Python expression: - o1*o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2); - - /* - This is the equivalent of the Python expression: o1 @ o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2); - - /* - Returns the result of dividing o1 by o2 giving an integral result, - or null on failure. - This is the equivalent of the Python expression: o1//o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2); - - /* - Returns the result of dividing o1 by o2 giving a float result, - or null on failure. - This is the equivalent of the Python expression: o1/o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); - - /* - Returns the remainder of dividing o1 by o2, or null on - failure. This is the equivalent of the Python expression: - o1%o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Divmod(PyObject *o1, PyObject *o2); - - /* - See the built-in function divmod. Returns NULL on failure. - This is the equivalent of the Python expression: - divmod(o1,o2). - */ - - PyAPI_FUNC(PyObject *) PyNumber_Power(PyObject *o1, PyObject *o2, - PyObject *o3); - - /* - See the built-in function pow. Returns NULL on failure. - This is the equivalent of the Python expression: - pow(o1,o2,o3), where o3 is optional. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Negative(PyObject *o); - - /* - Returns the negation of o on success, or null on failure. - This is the equivalent of the Python expression: -o. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Positive(PyObject *o); - - /* - Returns the (what?) of o on success, or NULL on failure. - This is the equivalent of the Python expression: +o. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Absolute(PyObject *o); - - /* - Returns the absolute value of o, or null on failure. This is - the equivalent of the Python expression: abs(o). - */ - - PyAPI_FUNC(PyObject *) PyNumber_Invert(PyObject *o); - - /* - Returns the bitwise negation of o on success, or NULL on - failure. This is the equivalent of the Python expression: - ~o. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Lshift(PyObject *o1, PyObject *o2); - - /* - Returns the result of left shifting o1 by o2 on success, or - NULL on failure. This is the equivalent of the Python - expression: o1 << o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Rshift(PyObject *o1, PyObject *o2); - - /* - Returns the result of right shifting o1 by o2 on success, or - NULL on failure. This is the equivalent of the Python - expression: o1 >> o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_And(PyObject *o1, PyObject *o2); - - /* - Returns the result of bitwise and of o1 and o2 on success, or - NULL on failure. This is the equivalent of the Python - expression: o1&o2. - - */ - - PyAPI_FUNC(PyObject *) PyNumber_Xor(PyObject *o1, PyObject *o2); - - /* - Returns the bitwise exclusive or of o1 by o2 on success, or - NULL on failure. This is the equivalent of the Python - expression: o1^o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Or(PyObject *o1, PyObject *o2); - - /* - Returns the result of bitwise or on o1 and o2 on success, or - NULL on failure. This is the equivalent of the Python - expression: o1|o2. - */ - -#define PyIndex_Check(obj) \ - ((obj)->ob_type->tp_as_number != NULL && \ - (obj)->ob_type->tp_as_number->nb_index != NULL) - - PyAPI_FUNC(PyObject *) PyNumber_Index(PyObject *o); - - /* - Returns the object converted to a Python int - or NULL with an error raised on failure. - */ - - PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); - - /* - Returns the object converted to Py_ssize_t by going through - PyNumber_Index first. If an overflow error occurs while - converting the int to Py_ssize_t, then the second argument - is the error-type to return. If it is NULL, then the overflow error - is cleared and the value is clipped. - */ - - PyAPI_FUNC(PyObject *) PyNumber_Long(PyObject *o); - - /* - Returns the o converted to an integer object on success, or - NULL on failure. This is the equivalent of the Python - expression: int(o). - */ - - PyAPI_FUNC(PyObject *) PyNumber_Float(PyObject *o); - - /* - Returns the o converted to a float object on success, or NULL - on failure. This is the equivalent of the Python expression: - float(o). - */ - -/* In-place variants of (some of) the above number protocol functions */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); - - /* - Returns the result of adding o2 to o1, possibly in-place, or null - on failure. This is the equivalent of the Python expression: - o1 += o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); - - /* - Returns the result of subtracting o2 from o1, possibly in-place or - null on failure. This is the equivalent of the Python expression: - o1 -= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); - - /* - Returns the result of multiplying o1 by o2, possibly in-place, or - null on failure. This is the equivalent of the Python expression: - o1 *= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2); - - /* - This is the equivalent of the Python expression: o1 @= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1, - PyObject *o2); - - /* - Returns the result of dividing o1 by o2 giving an integral result, - possibly in-place, or null on failure. - This is the equivalent of the Python expression: - o1 /= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1, - PyObject *o2); - - /* - Returns the result of dividing o1 by o2 giving a float result, - possibly in-place, or null on failure. - This is the equivalent of the Python expression: - o1 /= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); - - /* - Returns the remainder of dividing o1 by o2, possibly in-place, or - null on failure. This is the equivalent of the Python expression: - o1 %= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlacePower(PyObject *o1, PyObject *o2, - PyObject *o3); - - /* - Returns the result of raising o1 to the power of o2, possibly - in-place, or null on failure. This is the equivalent of the Python - expression: o1 **= o2, or pow(o1, o2, o3) if o3 is present. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); - - /* - Returns the result of left shifting o1 by o2, possibly in-place, or - null on failure. This is the equivalent of the Python expression: - o1 <<= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); - - /* - Returns the result of right shifting o1 by o2, possibly in-place or - null on failure. This is the equivalent of the Python expression: - o1 >>= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); - - /* - Returns the result of bitwise and of o1 and o2, possibly in-place, - or null on failure. This is the equivalent of the Python - expression: o1 &= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); - - /* - Returns the bitwise exclusive or of o1 by o2, possibly in-place, or - null on failure. This is the equivalent of the Python expression: - o1 ^= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); - - /* - Returns the result of bitwise or of o1 and o2, possibly in-place, - or null on failure. This is the equivalent of the Python - expression: o1 |= o2. - */ - - PyAPI_FUNC(PyObject *) PyNumber_ToBase(PyObject *n, int base); - - /* - Returns the integer n converted to a string with a base, with a base - marker of 0b, 0o or 0x prefixed if applicable. - If n is not an int object, it is converted with PyNumber_Index first. - */ - - -/* Sequence protocol:*/ - - PyAPI_FUNC(int) PySequence_Check(PyObject *o); - - /* - Return 1 if the object provides sequence protocol, and zero - otherwise. - - This function always succeeds. - */ - - PyAPI_FUNC(Py_ssize_t) PySequence_Size(PyObject *o); - - /* - Return the size of sequence object o, or -1 on failure. - */ - - /* For DLL compatibility */ -#undef PySequence_Length - PyAPI_FUNC(Py_ssize_t) PySequence_Length(PyObject *o); -#define PySequence_Length PySequence_Size - - - PyAPI_FUNC(PyObject *) PySequence_Concat(PyObject *o1, PyObject *o2); - - /* - Return the concatenation of o1 and o2 on success, and NULL on - failure. This is the equivalent of the Python - expression: o1+o2. - */ - - PyAPI_FUNC(PyObject *) PySequence_Repeat(PyObject *o, Py_ssize_t count); - - /* - Return the result of repeating sequence object o count times, - or NULL on failure. This is the equivalent of the Python - expression: o1*count. - */ - - PyAPI_FUNC(PyObject *) PySequence_GetItem(PyObject *o, Py_ssize_t i); - - /* - Return the ith element of o, or NULL on failure. This is the - equivalent of the Python expression: o[i]. - */ - - PyAPI_FUNC(PyObject *) PySequence_GetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); - - /* - Return the slice of sequence object o between i1 and i2, or - NULL on failure. This is the equivalent of the Python - expression: o[i1:i2]. - */ - - PyAPI_FUNC(int) PySequence_SetItem(PyObject *o, Py_ssize_t i, PyObject *v); - - /* - Assign object v to the ith element of o. Raise an exception and return - -1 on failure; return 0 on success. This is the equivalent of the - Python statement o[i]=v. - */ - - PyAPI_FUNC(int) PySequence_DelItem(PyObject *o, Py_ssize_t i); - - /* - Delete the ith element of object v. Returns - -1 on failure. This is the equivalent of the Python - statement: del o[i]. - */ - - PyAPI_FUNC(int) PySequence_SetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2, - PyObject *v); - - /* - Assign the sequence object, v, to the slice in sequence - object, o, from i1 to i2. Returns -1 on failure. This is the - equivalent of the Python statement: o[i1:i2]=v. - */ - - PyAPI_FUNC(int) PySequence_DelSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); - - /* - Delete the slice in sequence object, o, from i1 to i2. - Returns -1 on failure. This is the equivalent of the Python - statement: del o[i1:i2]. - */ - - PyAPI_FUNC(PyObject *) PySequence_Tuple(PyObject *o); - - /* - Returns the sequence, o, as a tuple on success, and NULL on failure. - This is equivalent to the Python expression: tuple(o) - */ - - - PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); - /* - Returns the sequence, o, as a list on success, and NULL on failure. - This is equivalent to the Python expression: list(o) - */ - - PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); - /* - Return the sequence, o, as a list, unless it's already a - tuple or list. Use PySequence_Fast_GET_ITEM to access the - members of this list, and PySequence_Fast_GET_SIZE to get its length. - - Returns NULL on failure. If the object does not support iteration, - raises a TypeError exception with m as the message text. - */ - -#define PySequence_Fast_GET_SIZE(o) \ - (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) - /* - Return the size of o, assuming that o was returned by - PySequence_Fast and is not NULL. - */ - -#define PySequence_Fast_GET_ITEM(o, i)\ - (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) - /* - Return the ith element of o, assuming that o was returned by - PySequence_Fast, and that i is within bounds. - */ - -#define PySequence_ITEM(o, i)\ - ( Py_TYPE(o)->tp_as_sequence->sq_item(o, i) ) - /* Assume tp_as_sequence and sq_item exist and that i does not - need to be corrected for a negative index - */ - -#define PySequence_Fast_ITEMS(sf) \ - (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ - : ((PyTupleObject *)(sf))->ob_item) - /* Return a pointer to the underlying item array for - an object retured by PySequence_Fast */ - - PyAPI_FUNC(Py_ssize_t) PySequence_Count(PyObject *o, PyObject *value); - - /* - Return the number of occurrences on value on o, that is, - return the number of keys for which o[key]==value. On - failure, return -1. This is equivalent to the Python - expression: o.count(value). - */ - - PyAPI_FUNC(int) PySequence_Contains(PyObject *seq, PyObject *ob); - /* - Return -1 if error; 1 if ob in seq; 0 if ob not in seq. - Use __contains__ if possible, else _PySequence_IterSearch(). - */ - -#ifndef Py_LIMITED_API -#define PY_ITERSEARCH_COUNT 1 -#define PY_ITERSEARCH_INDEX 2 -#define PY_ITERSEARCH_CONTAINS 3 - PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, - PyObject *obj, int operation); -#endif - /* - Iterate over seq. Result depends on the operation: - PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if - error. - PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of - obj in seq; set ValueError and return -1 if none found; - also return -1 on error. - PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on - error. - */ - -/* For DLL-level backwards compatibility */ -#undef PySequence_In - PyAPI_FUNC(int) PySequence_In(PyObject *o, PyObject *value); - -/* For source-level backwards compatibility */ -#define PySequence_In PySequence_Contains - - /* - Determine if o contains value. If an item in o is equal to - X, return 1, otherwise return 0. On error, return -1. This - is equivalent to the Python expression: value in o. - */ - - PyAPI_FUNC(Py_ssize_t) PySequence_Index(PyObject *o, PyObject *value); - - /* - Return the first index for which o[i]=value. On error, - return -1. This is equivalent to the Python - expression: o.index(value). - */ - -/* In-place versions of some of the above Sequence functions. */ - - PyAPI_FUNC(PyObject *) PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); - - /* - Append o2 to o1, in-place when possible. Return the resulting - object, which could be o1, or NULL on failure. This is the - equivalent of the Python expression: o1 += o2. - - */ - - PyAPI_FUNC(PyObject *) PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count); - - /* - Repeat o1 by count, in-place when possible. Return the resulting - object, which could be o1, or NULL on failure. This is the - equivalent of the Python expression: o1 *= count. - - */ - -/* Mapping protocol:*/ - - PyAPI_FUNC(int) PyMapping_Check(PyObject *o); - - /* - Return 1 if the object provides mapping protocol, and zero - otherwise. - - This function always succeeds. - */ - - PyAPI_FUNC(Py_ssize_t) PyMapping_Size(PyObject *o); - - /* - Returns the number of keys in object o on success, and -1 on - failure. For objects that do not provide sequence protocol, - this is equivalent to the Python expression: len(o). - */ - - /* For DLL compatibility */ -#undef PyMapping_Length - PyAPI_FUNC(Py_ssize_t) PyMapping_Length(PyObject *o); -#define PyMapping_Length PyMapping_Size - - - /* implemented as a macro: - - int PyMapping_DelItemString(PyObject *o, const char *key); - - Remove the mapping for object, key, from the object *o. - Returns -1 on failure. This is equivalent to - the Python statement: del o[key]. - */ -#define PyMapping_DelItemString(O,K) PyObject_DelItemString((O),(K)) - - /* implemented as a macro: - - int PyMapping_DelItem(PyObject *o, PyObject *key); - - Remove the mapping for object, key, from the object *o. - Returns -1 on failure. This is equivalent to - the Python statement: del o[key]. - */ -#define PyMapping_DelItem(O,K) PyObject_DelItem((O),(K)) - - PyAPI_FUNC(int) PyMapping_HasKeyString(PyObject *o, const char *key); - - /* - On success, return 1 if the mapping object has the key, key, - and 0 otherwise. This is equivalent to the Python expression: - key in o. - - This function always succeeds. - */ - - PyAPI_FUNC(int) PyMapping_HasKey(PyObject *o, PyObject *key); - - /* - Return 1 if the mapping object has the key, key, - and 0 otherwise. This is equivalent to the Python expression: - key in o. - - This function always succeeds. - - */ - - PyAPI_FUNC(PyObject *) PyMapping_Keys(PyObject *o); - - /* - On success, return a list or tuple of the keys in object o. - On failure, return NULL. - */ - - PyAPI_FUNC(PyObject *) PyMapping_Values(PyObject *o); - - /* - On success, return a list or tuple of the values in object o. - On failure, return NULL. - */ - - PyAPI_FUNC(PyObject *) PyMapping_Items(PyObject *o); - - /* - On success, return a list or tuple of the items in object o, - where each item is a tuple containing a key-value pair. - On failure, return NULL. - - */ - - PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, - const char *key); - - /* - Return element of o corresponding to the object, key, or NULL - on failure. This is the equivalent of the Python expression: - o[key]. - */ - - PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, const char *key, - PyObject *value); - - /* - Map the object, key, to the value, v. Returns - -1 on failure. This is the equivalent of the Python - statement: o[key]=v. - */ - - -PyAPI_FUNC(int) PyObject_IsInstance(PyObject *object, PyObject *typeorclass); - /* isinstance(object, typeorclass) */ - -PyAPI_FUNC(int) PyObject_IsSubclass(PyObject *object, PyObject *typeorclass); - /* issubclass(object, typeorclass) */ - - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); - -PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); - -PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); - -PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); -#endif - -/* For internal use by buffer API functions */ -PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); -PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); - - -#ifdef __cplusplus -} -#endif -#endif /* Py_ABSTRACTOBJECT_H */ +#ifndef Py_ABSTRACTOBJECT_H +#define Py_ABSTRACTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PY_SSIZE_T_CLEAN +#define PyObject_CallFunction _PyObject_CallFunction_SizeT +#define PyObject_CallMethod _PyObject_CallMethod_SizeT +#define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT +#endif + +/* Abstract Object Interface (many thanks to Jim Fulton) */ + +/* + PROPOSAL: A Generic Python Object Interface for Python C Modules + +Problem + + Python modules written in C that must access Python objects must do + so through routines whose interfaces are described by a set of + include files. Unfortunately, these routines vary according to the + object accessed. To use these routines, the C programmer must check + the type of the object being used and must call a routine based on + the object type. For example, to access an element of a sequence, + the programmer must determine whether the sequence is a list or a + tuple: + + if(is_tupleobject(o)) + e=gettupleitem(o,i) + else if(is_listitem(o)) + e=getlistitem(o,i) + + If the programmer wants to get an item from another type of object + that provides sequence behavior, there is no clear way to do it + correctly. + + The persistent programmer may peruse object.h and find that the + _typeobject structure provides a means of invoking up to (currently + about) 41 special operators. So, for example, a routine can get an + item from any object that provides sequence behavior. However, to + use this mechanism, the programmer must make their code dependent on + the current Python implementation. + + Also, certain semantics, especially memory management semantics, may + differ by the type of object being used. Unfortunately, these + semantics are not clearly described in the current include files. + An abstract interface providing more consistent semantics is needed. + +Proposal + + I propose the creation of a standard interface (with an associated + library of routines and/or macros) for generically obtaining the + services of Python objects. This proposal can be viewed as one + components of a Python C interface consisting of several components. + + From the viewpoint of C access to Python services, we have (as + suggested by Guido in off-line discussions): + + - "Very high level layer": two or three functions that let you exec or + eval arbitrary Python code given as a string in a module whose name is + given, passing C values in and getting C values out using + mkvalue/getargs style format strings. This does not require the user + to declare any variables of type "PyObject *". This should be enough + to write a simple application that gets Python code from the user, + execs it, and returns the output or errors. (Error handling must also + be part of this API.) + + - "Abstract objects layer": which is the subject of this proposal. + It has many functions operating on objects, and lest you do many + things from C that you can also write in Python, without going + through the Python parser. + + - "Concrete objects layer": This is the public type-dependent + interface provided by the standard built-in types, such as floats, + strings, and lists. This interface exists and is currently + documented by the collection of include files provided with the + Python distributions. + + From the point of view of Python accessing services provided by C + modules: + + - "Python module interface": this interface consist of the basic + routines used to define modules and their members. Most of the + current extensions-writing guide deals with this interface. + + - "Built-in object interface": this is the interface that a new + built-in type must provide and the mechanisms and rules that a + developer of a new built-in type must use and follow. + + This proposal is a "first-cut" that is intended to spur + discussion. See especially the lists of notes. + + The Python C object interface will provide four protocols: object, + numeric, sequence, and mapping. Each protocol consists of a + collection of related operations. If an operation that is not + provided by a particular type is invoked, then a standard exception, + NotImplementedError is raised with an operation name as an argument. + In addition, for convenience this interface defines a set of + constructors for building objects of built-in types. This is needed + so new objects can be returned from C functions that otherwise treat + objects generically. + +Memory Management + + For all of the functions described in this proposal, if a function + retains a reference to a Python object passed as an argument, then the + function will increase the reference count of the object. It is + unnecessary for the caller to increase the reference count of an + argument in anticipation of the object's retention. + + All Python objects returned from functions should be treated as new + objects. Functions that return objects assume that the caller will + retain a reference and the reference count of the object has already + been incremented to account for this fact. A caller that does not + retain a reference to an object that is returned from a function + must decrement the reference count of the object (using + DECREF(object)) to prevent memory leaks. + + Note that the behavior mentioned here is different from the current + behavior for some objects (e.g. lists and tuples) when certain + type-specific routines are called directly (e.g. setlistitem). The + proposed abstraction layer will provide a consistent memory + management interface, correcting for inconsistent behavior for some + built-in types. + +Protocols + +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ + +/* Object Protocol: */ + + /* Implemented elsewhere: + + int PyObject_Print(PyObject *o, FILE *fp, int flags); + + Print an object, o, on file, fp. Returns -1 on + error. The flags argument is used to enable certain printing + options. The only option currently supported is Py_Print_RAW. + + (What should be said about Py_Print_RAW?) + + */ + + /* Implemented elsewhere: + + int PyObject_HasAttrString(PyObject *o, const char *attr_name); + + Returns 1 if o has the attribute attr_name, and 0 otherwise. + This is equivalent to the Python expression: + hasattr(o,attr_name). + + This function always succeeds. + + */ + + /* Implemented elsewhere: + + PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name); + + Retrieve an attributed named attr_name form object o. + Returns the attribute value on success, or NULL on failure. + This is the equivalent of the Python expression: o.attr_name. + + */ + + /* Implemented elsewhere: + + int PyObject_HasAttr(PyObject *o, PyObject *attr_name); + + Returns 1 if o has the attribute attr_name, and 0 otherwise. + This is equivalent to the Python expression: + hasattr(o,attr_name). + + This function always succeeds. + + */ + + /* Implemented elsewhere: + + PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name); + + Retrieve an attributed named attr_name form object o. + Returns the attribute value on success, or NULL on failure. + This is the equivalent of the Python expression: o.attr_name. + + */ + + + /* Implemented elsewhere: + + int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v); + + Set the value of the attribute named attr_name, for object o, + to the value v. Raise an exception and return -1 on failure; return 0 on + success. This is the equivalent of the Python statement o.attr_name=v. + + */ + + /* Implemented elsewhere: + + int PyObject_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v); + + Set the value of the attribute named attr_name, for object o, + to the value v. Raise an exception and return -1 on failure; return 0 on + success. This is the equivalent of the Python statement o.attr_name=v. + + */ + + /* implemented as a macro: + + int PyObject_DelAttrString(PyObject *o, const char *attr_name); + + Delete attribute named attr_name, for object o. Returns + -1 on failure. This is the equivalent of the Python + statement: del o.attr_name. + + */ +#define PyObject_DelAttrString(O,A) PyObject_SetAttrString((O),(A),NULL) + + /* implemented as a macro: + + int PyObject_DelAttr(PyObject *o, PyObject *attr_name); + + Delete attribute named attr_name, for object o. Returns -1 + on failure. This is the equivalent of the Python + statement: del o.attr_name. + + */ +#define PyObject_DelAttr(O,A) PyObject_SetAttr((O),(A),NULL) + + /* Implemented elsewhere: + + PyObject *PyObject_Repr(PyObject *o); + + Compute the string representation of object, o. Returns the + string representation on success, NULL on failure. This is + the equivalent of the Python expression: repr(o). + + Called by the repr() built-in function. + + */ + + /* Implemented elsewhere: + + PyObject *PyObject_Str(PyObject *o); + + Compute the string representation of object, o. Returns the + string representation on success, NULL on failure. This is + the equivalent of the Python expression: str(o).) + + Called by the str() and print() built-in functions. + + */ + + /* Declared elsewhere + + PyAPI_FUNC(int) PyCallable_Check(PyObject *o); + + Determine if the object, o, is callable. Return 1 if the + object is callable and 0 otherwise. + + This function always succeeds. + */ + + PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, + PyObject *args, PyObject *kw); + + /* + Call a callable Python object, callable_object, with + arguments and keywords arguments. The 'args' argument can not be + NULL, but the 'kw' argument can be NULL. + */ + +#ifndef Py_LIMITED_API + PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, + PyObject *result, + const char *where); +#endif + + PyAPI_FUNC(PyObject *) PyObject_CallObject(PyObject *callable_object, + PyObject *args); + + /* + Call a callable Python object, callable_object, with + arguments given by the tuple, args. If no arguments are + needed, then args may be NULL. Returns the result of the + call on success, or NULL on failure. This is the equivalent + of the Python expression: o(*args). + */ + + PyAPI_FUNC(PyObject *) PyObject_CallFunction(PyObject *callable_object, + const char *format, ...); + + /* + Call a callable Python object, callable_object, with a + variable number of C arguments. The C arguments are described + using a mkvalue-style format string. The format may be NULL, + indicating that no arguments are provided. Returns the + result of the call on success, or NULL on failure. This is + the equivalent of the Python expression: o(*args). + */ + + + PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *o, + const char *method, + const char *format, ...); + + /* + Call the method named m of object o with a variable number of + C arguments. The C arguments are described by a mkvalue + format string. The format may be NULL, indicating that no + arguments are provided. Returns the result of the call on + success, or NULL on failure. This is the equivalent of the + Python expression: o.method(args). + */ + + PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *o, + _Py_Identifier *method, + const char *format, ...); + + /* + Like PyObject_CallMethod, but expect a _Py_Identifier* as the + method name. + */ + + PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, + const char *format, + ...); + PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *o, + const char *name, + const char *format, + ...); + PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *o, + _Py_Identifier *name, + const char *format, + ...); + + PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable, + ...); + + /* + Call a callable Python object, callable_object, with a + variable number of C arguments. The C arguments are provided + as PyObject * values, terminated by a NULL. Returns the + result of the call on success, or NULL on failure. This is + the equivalent of the Python expression: o(*args). + */ + + + PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs(PyObject *o, + PyObject *method, ...); + PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs(PyObject *o, + struct _Py_Identifier *method, + ...); + + /* + Call the method named m of object o with a variable number of + C arguments. The C arguments are provided as PyObject * + values, terminated by NULL. Returns the result of the call + on success, or NULL on failure. This is the equivalent of + the Python expression: o.method(args). + */ + + + /* Implemented elsewhere: + + long PyObject_Hash(PyObject *o); + + Compute and return the hash, hash_value, of an object, o. On + failure, return -1. This is the equivalent of the Python + expression: hash(o). + */ + + + /* Implemented elsewhere: + + int PyObject_IsTrue(PyObject *o); + + Returns 1 if the object, o, is considered to be true, 0 if o is + considered to be false and -1 on failure. This is equivalent to the + Python expression: not not o + */ + + /* Implemented elsewhere: + + int PyObject_Not(PyObject *o); + + Returns 0 if the object, o, is considered to be true, 1 if o is + considered to be false and -1 on failure. This is equivalent to the + Python expression: not o + */ + + PyAPI_FUNC(PyObject *) PyObject_Type(PyObject *o); + + /* + On success, returns a type object corresponding to the object + type of object o. On failure, returns NULL. This is + equivalent to the Python expression: type(o). + */ + + PyAPI_FUNC(Py_ssize_t) PyObject_Size(PyObject *o); + + /* + Return the size of object o. If the object, o, provides + both sequence and mapping protocols, the sequence size is + returned. On error, -1 is returned. This is the equivalent + to the Python expression: len(o). + */ + + /* For DLL compatibility */ +#undef PyObject_Length + PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o); +#define PyObject_Length PyObject_Size + +#ifndef Py_LIMITED_API + PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); + PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); +#endif + + /* + Guess the size of object o using len(o) or o.__length_hint__(). + If neither of those return a non-negative value, then return the + default value. If one of the calls fails, this function returns -1. + */ + + PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); + + /* + Return element of o corresponding to the object, key, or NULL + on failure. This is the equivalent of the Python expression: + o[key]. + */ + + PyAPI_FUNC(int) PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v); + + /* + Map the object key to the value v. Raise an exception and return -1 + on failure; return 0 on success. This is the equivalent of the Python + statement o[key]=v. + */ + + PyAPI_FUNC(int) PyObject_DelItemString(PyObject *o, const char *key); + + /* + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ + + PyAPI_FUNC(int) PyObject_DelItem(PyObject *o, PyObject *key); + + /* + Delete the mapping for key from *o. Returns -1 on failure. + This is the equivalent of the Python statement: del o[key]. + */ + + /* old buffer API + FIXME: usage of these should all be replaced in Python itself + but for backwards compatibility we will implement them. + Their usage without a corresponding "unlock" mechanism + may create issues (but they would already be there). */ + + PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj, + const char **buffer, + Py_ssize_t *buffer_len); + + /* + Takes an arbitrary object which must support the (character, + single segment) buffer interface and returns a pointer to a + read-only memory location useable as character based input + for subsequent processing. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurs. Otherwise, -1 is returned and + an exception set. + */ + + PyAPI_FUNC(int) PyObject_CheckReadBuffer(PyObject *obj); + + /* + Checks whether an arbitrary object supports the (character, + single segment) buffer interface. Returns 1 on success, 0 + on failure. + */ + + PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *obj, + const void **buffer, + Py_ssize_t *buffer_len); + + /* + Same as PyObject_AsCharBuffer() except that this API expects + (readable, single segment) buffer interface and returns a + pointer to a read-only memory location which can contain + arbitrary data. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurs. Otherwise, -1 is returned and + an exception set. + */ + + PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj, + void **buffer, + Py_ssize_t *buffer_len); + + /* + Takes an arbitrary object which must support the (writable, + single segment) buffer interface and returns a pointer to a + writable memory location in buffer of size buffer_len. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurs. Otherwise, -1 is returned and + an exception set. + */ + + /* new buffer API */ + +#ifndef Py_LIMITED_API +#define PyObject_CheckBuffer(obj) \ + (((obj)->ob_type->tp_as_buffer != NULL) && \ + ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL)) + + /* Return 1 if the getbuffer function is available, otherwise + return 0 */ + + PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, + int flags); + + /* This is a C-API version of the getbuffer function call. It checks + to make sure object has the required function pointer and issues the + call. Returns -1 and raises an error on failure and returns 0 on + success + */ + + + PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); + + /* Get the memory area pointed to by the indices for the buffer given. + Note that view->ndim is the assumed size of indices + */ + + PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *); + + /* Return the implied itemsize of the data-format area from a + struct-style description */ + + + + /* Implementation in memoryobject.c */ + PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, + Py_ssize_t len, char order); + + PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, + Py_ssize_t len, char order); + + + /* Copy len bytes of data from the contiguous chunk of memory + pointed to by buf into the buffer exported by obj. Return + 0 on success and return -1 and raise a PyBuffer_Error on + error (i.e. the object does not have a buffer interface or + it is not working). + + If fort is 'F', then if the object is multi-dimensional, + then the data will be copied into the array in + Fortran-style (first dimension varies the fastest). If + fort is 'C', then the data will be copied into the array + in C-style (last dimension varies the fastest). If fort + is 'A', then it does not matter and the copy will be made + in whatever way is more efficient. + + */ + + PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); + + /* Copy the data from the src buffer to the buffer of destination + */ + + PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); + + + PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, + Py_ssize_t *shape, + Py_ssize_t *strides, + int itemsize, + char fort); + + /* Fill the strides array with byte-strides of a contiguous + (Fortran-style if fort is 'F' or C-style otherwise) + array of the given shape with the given number of bytes + per element. + */ + + PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, + Py_ssize_t len, int readonly, + int flags); + + /* Fills in a buffer-info structure correctly for an exporter + that can only share a contiguous chunk of memory of + "unsigned bytes" of the given length. Returns 0 on success + and -1 (with raising an error) on error. + */ + + PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); + + /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*. + */ +#endif /* Py_LIMITED_API */ + + PyAPI_FUNC(PyObject *) PyObject_Format(PyObject* obj, + PyObject *format_spec); + /* + Takes an arbitrary object and returns the result of + calling obj.__format__(format_spec). + */ + +/* Iterators */ + + PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *); + /* Takes an object and returns an iterator for it. + This is typically a new iterator but if the argument + is an iterator, this returns itself. */ + +#define PyIter_Check(obj) \ + ((obj)->ob_type->tp_iternext != NULL && \ + (obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented) + + PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *); + /* Takes an iterator object and calls its tp_iternext slot, + returning the next value. If the iterator is exhausted, + this returns NULL without setting an exception. + NULL with an exception means an error occurred. */ + +/* Number Protocol:*/ + + PyAPI_FUNC(int) PyNumber_Check(PyObject *o); + + /* + Returns 1 if the object, o, provides numeric protocols, and + false otherwise. + + This function always succeeds. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Add(PyObject *o1, PyObject *o2); + + /* + Returns the result of adding o1 and o2, or null on failure. + This is the equivalent of the Python expression: o1+o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Subtract(PyObject *o1, PyObject *o2); + + /* + Returns the result of subtracting o2 from o1, or null on + failure. This is the equivalent of the Python expression: + o1-o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Multiply(PyObject *o1, PyObject *o2); + + /* + Returns the result of multiplying o1 and o2, or null on + failure. This is the equivalent of the Python expression: + o1*o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2); + + /* + This is the equivalent of the Python expression: o1 @ o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving an integral result, + or null on failure. + This is the equivalent of the Python expression: o1//o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving a float result, + or null on failure. + This is the equivalent of the Python expression: o1/o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); + + /* + Returns the remainder of dividing o1 by o2, or null on + failure. This is the equivalent of the Python expression: + o1%o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Divmod(PyObject *o1, PyObject *o2); + + /* + See the built-in function divmod. Returns NULL on failure. + This is the equivalent of the Python expression: + divmod(o1,o2). + */ + + PyAPI_FUNC(PyObject *) PyNumber_Power(PyObject *o1, PyObject *o2, + PyObject *o3); + + /* + See the built-in function pow. Returns NULL on failure. + This is the equivalent of the Python expression: + pow(o1,o2,o3), where o3 is optional. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Negative(PyObject *o); + + /* + Returns the negation of o on success, or null on failure. + This is the equivalent of the Python expression: -o. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Positive(PyObject *o); + + /* + Returns the (what?) of o on success, or NULL on failure. + This is the equivalent of the Python expression: +o. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Absolute(PyObject *o); + + /* + Returns the absolute value of o, or null on failure. This is + the equivalent of the Python expression: abs(o). + */ + + PyAPI_FUNC(PyObject *) PyNumber_Invert(PyObject *o); + + /* + Returns the bitwise negation of o on success, or NULL on + failure. This is the equivalent of the Python expression: + ~o. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Lshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of left shifting o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1 << o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Rshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of right shifting o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1 >> o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_And(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise and of o1 and o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1&o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Xor(PyObject *o1, PyObject *o2); + + /* + Returns the bitwise exclusive or of o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1^o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Or(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise or on o1 and o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1|o2. + */ + +#define PyIndex_Check(obj) \ + ((obj)->ob_type->tp_as_number != NULL && \ + (obj)->ob_type->tp_as_number->nb_index != NULL) + + PyAPI_FUNC(PyObject *) PyNumber_Index(PyObject *o); + + /* + Returns the object converted to a Python int + or NULL with an error raised on failure. + */ + + PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); + + /* + Returns the object converted to Py_ssize_t by going through + PyNumber_Index first. If an overflow error occurs while + converting the int to Py_ssize_t, then the second argument + is the error-type to return. If it is NULL, then the overflow error + is cleared and the value is clipped. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Long(PyObject *o); + + /* + Returns the o converted to an integer object on success, or + NULL on failure. This is the equivalent of the Python + expression: int(o). + */ + + PyAPI_FUNC(PyObject *) PyNumber_Float(PyObject *o); + + /* + Returns the o converted to a float object on success, or NULL + on failure. This is the equivalent of the Python expression: + float(o). + */ + +/* In-place variants of (some of) the above number protocol functions */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); + + /* + Returns the result of adding o2 to o1, possibly in-place, or null + on failure. This is the equivalent of the Python expression: + o1 += o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); + + /* + Returns the result of subtracting o2 from o1, possibly in-place or + null on failure. This is the equivalent of the Python expression: + o1 -= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); + + /* + Returns the result of multiplying o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 *= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2); + + /* + This is the equivalent of the Python expression: o1 @= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1, + PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving an integral result, + possibly in-place, or null on failure. + This is the equivalent of the Python expression: + o1 /= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1, + PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving a float result, + possibly in-place, or null on failure. + This is the equivalent of the Python expression: + o1 /= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); + + /* + Returns the remainder of dividing o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 %= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlacePower(PyObject *o1, PyObject *o2, + PyObject *o3); + + /* + Returns the result of raising o1 to the power of o2, possibly + in-place, or null on failure. This is the equivalent of the Python + expression: o1 **= o2, or pow(o1, o2, o3) if o3 is present. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of left shifting o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 <<= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of right shifting o1 by o2, possibly in-place or + null on failure. This is the equivalent of the Python expression: + o1 >>= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise and of o1 and o2, possibly in-place, + or null on failure. This is the equivalent of the Python + expression: o1 &= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); + + /* + Returns the bitwise exclusive or of o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 ^= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise or of o1 and o2, possibly in-place, + or null on failure. This is the equivalent of the Python + expression: o1 |= o2. + */ + + PyAPI_FUNC(PyObject *) PyNumber_ToBase(PyObject *n, int base); + + /* + Returns the integer n converted to a string with a base, with a base + marker of 0b, 0o or 0x prefixed if applicable. + If n is not an int object, it is converted with PyNumber_Index first. + */ + + +/* Sequence protocol:*/ + + PyAPI_FUNC(int) PySequence_Check(PyObject *o); + + /* + Return 1 if the object provides sequence protocol, and zero + otherwise. + + This function always succeeds. + */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Size(PyObject *o); + + /* + Return the size of sequence object o, or -1 on failure. + */ + + /* For DLL compatibility */ +#undef PySequence_Length + PyAPI_FUNC(Py_ssize_t) PySequence_Length(PyObject *o); +#define PySequence_Length PySequence_Size + + + PyAPI_FUNC(PyObject *) PySequence_Concat(PyObject *o1, PyObject *o2); + + /* + Return the concatenation of o1 and o2 on success, and NULL on + failure. This is the equivalent of the Python + expression: o1+o2. + */ + + PyAPI_FUNC(PyObject *) PySequence_Repeat(PyObject *o, Py_ssize_t count); + + /* + Return the result of repeating sequence object o count times, + or NULL on failure. This is the equivalent of the Python + expression: o1*count. + */ + + PyAPI_FUNC(PyObject *) PySequence_GetItem(PyObject *o, Py_ssize_t i); + + /* + Return the ith element of o, or NULL on failure. This is the + equivalent of the Python expression: o[i]. + */ + + PyAPI_FUNC(PyObject *) PySequence_GetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); + + /* + Return the slice of sequence object o between i1 and i2, or + NULL on failure. This is the equivalent of the Python + expression: o[i1:i2]. + */ + + PyAPI_FUNC(int) PySequence_SetItem(PyObject *o, Py_ssize_t i, PyObject *v); + + /* + Assign object v to the ith element of o. Raise an exception and return + -1 on failure; return 0 on success. This is the equivalent of the + Python statement o[i]=v. + */ + + PyAPI_FUNC(int) PySequence_DelItem(PyObject *o, Py_ssize_t i); + + /* + Delete the ith element of object v. Returns + -1 on failure. This is the equivalent of the Python + statement: del o[i]. + */ + + PyAPI_FUNC(int) PySequence_SetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2, + PyObject *v); + + /* + Assign the sequence object, v, to the slice in sequence + object, o, from i1 to i2. Returns -1 on failure. This is the + equivalent of the Python statement: o[i1:i2]=v. + */ + + PyAPI_FUNC(int) PySequence_DelSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); + + /* + Delete the slice in sequence object, o, from i1 to i2. + Returns -1 on failure. This is the equivalent of the Python + statement: del o[i1:i2]. + */ + + PyAPI_FUNC(PyObject *) PySequence_Tuple(PyObject *o); + + /* + Returns the sequence, o, as a tuple on success, and NULL on failure. + This is equivalent to the Python expression: tuple(o) + */ + + + PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); + /* + Returns the sequence, o, as a list on success, and NULL on failure. + This is equivalent to the Python expression: list(o) + */ + + PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); + /* + Return the sequence, o, as a list, unless it's already a + tuple or list. Use PySequence_Fast_GET_ITEM to access the + members of this list, and PySequence_Fast_GET_SIZE to get its length. + + Returns NULL on failure. If the object does not support iteration, + raises a TypeError exception with m as the message text. + */ + +#define PySequence_Fast_GET_SIZE(o) \ + (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) + /* + Return the size of o, assuming that o was returned by + PySequence_Fast and is not NULL. + */ + +#define PySequence_Fast_GET_ITEM(o, i)\ + (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) + /* + Return the ith element of o, assuming that o was returned by + PySequence_Fast, and that i is within bounds. + */ + +#define PySequence_ITEM(o, i)\ + ( Py_TYPE(o)->tp_as_sequence->sq_item(o, i) ) + /* Assume tp_as_sequence and sq_item exist and that i does not + need to be corrected for a negative index + */ + +#define PySequence_Fast_ITEMS(sf) \ + (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ + : ((PyTupleObject *)(sf))->ob_item) + /* Return a pointer to the underlying item array for + an object retured by PySequence_Fast */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Count(PyObject *o, PyObject *value); + + /* + Return the number of occurrences on value on o, that is, + return the number of keys for which o[key]==value. On + failure, return -1. This is equivalent to the Python + expression: o.count(value). + */ + + PyAPI_FUNC(int) PySequence_Contains(PyObject *seq, PyObject *ob); + /* + Return -1 if error; 1 if ob in seq; 0 if ob not in seq. + Use __contains__ if possible, else _PySequence_IterSearch(). + */ + +#ifndef Py_LIMITED_API +#define PY_ITERSEARCH_COUNT 1 +#define PY_ITERSEARCH_INDEX 2 +#define PY_ITERSEARCH_CONTAINS 3 + PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, + PyObject *obj, int operation); +#endif + /* + Iterate over seq. Result depends on the operation: + PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if + error. + PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of + obj in seq; set ValueError and return -1 if none found; + also return -1 on error. + PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on + error. + */ + +/* For DLL-level backwards compatibility */ +#undef PySequence_In + PyAPI_FUNC(int) PySequence_In(PyObject *o, PyObject *value); + +/* For source-level backwards compatibility */ +#define PySequence_In PySequence_Contains + + /* + Determine if o contains value. If an item in o is equal to + X, return 1, otherwise return 0. On error, return -1. This + is equivalent to the Python expression: value in o. + */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Index(PyObject *o, PyObject *value); + + /* + Return the first index for which o[i]=value. On error, + return -1. This is equivalent to the Python + expression: o.index(value). + */ + +/* In-place versions of some of the above Sequence functions. */ + + PyAPI_FUNC(PyObject *) PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); + + /* + Append o2 to o1, in-place when possible. Return the resulting + object, which could be o1, or NULL on failure. This is the + equivalent of the Python expression: o1 += o2. + + */ + + PyAPI_FUNC(PyObject *) PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count); + + /* + Repeat o1 by count, in-place when possible. Return the resulting + object, which could be o1, or NULL on failure. This is the + equivalent of the Python expression: o1 *= count. + + */ + +/* Mapping protocol:*/ + + PyAPI_FUNC(int) PyMapping_Check(PyObject *o); + + /* + Return 1 if the object provides mapping protocol, and zero + otherwise. + + This function always succeeds. + */ + + PyAPI_FUNC(Py_ssize_t) PyMapping_Size(PyObject *o); + + /* + Returns the number of keys in object o on success, and -1 on + failure. For objects that do not provide sequence protocol, + this is equivalent to the Python expression: len(o). + */ + + /* For DLL compatibility */ +#undef PyMapping_Length + PyAPI_FUNC(Py_ssize_t) PyMapping_Length(PyObject *o); +#define PyMapping_Length PyMapping_Size + + + /* implemented as a macro: + + int PyMapping_DelItemString(PyObject *o, const char *key); + + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ +#define PyMapping_DelItemString(O,K) PyObject_DelItemString((O),(K)) + + /* implemented as a macro: + + int PyMapping_DelItem(PyObject *o, PyObject *key); + + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ +#define PyMapping_DelItem(O,K) PyObject_DelItem((O),(K)) + + PyAPI_FUNC(int) PyMapping_HasKeyString(PyObject *o, const char *key); + + /* + On success, return 1 if the mapping object has the key, key, + and 0 otherwise. This is equivalent to the Python expression: + key in o. + + This function always succeeds. + */ + + PyAPI_FUNC(int) PyMapping_HasKey(PyObject *o, PyObject *key); + + /* + Return 1 if the mapping object has the key, key, + and 0 otherwise. This is equivalent to the Python expression: + key in o. + + This function always succeeds. + + */ + + PyAPI_FUNC(PyObject *) PyMapping_Keys(PyObject *o); + + /* + On success, return a list or tuple of the keys in object o. + On failure, return NULL. + */ + + PyAPI_FUNC(PyObject *) PyMapping_Values(PyObject *o); + + /* + On success, return a list or tuple of the values in object o. + On failure, return NULL. + */ + + PyAPI_FUNC(PyObject *) PyMapping_Items(PyObject *o); + + /* + On success, return a list or tuple of the items in object o, + where each item is a tuple containing a key-value pair. + On failure, return NULL. + + */ + + PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, + const char *key); + + /* + Return element of o corresponding to the object, key, or NULL + on failure. This is the equivalent of the Python expression: + o[key]. + */ + + PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, const char *key, + PyObject *value); + + /* + Map the object, key, to the value, v. Returns + -1 on failure. This is the equivalent of the Python + statement: o[key]=v. + */ + + +PyAPI_FUNC(int) PyObject_IsInstance(PyObject *object, PyObject *typeorclass); + /* isinstance(object, typeorclass) */ + +PyAPI_FUNC(int) PyObject_IsSubclass(PyObject *object, PyObject *typeorclass); + /* issubclass(object, typeorclass) */ + + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); + +PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); + +PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); + +PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); +#endif + +/* For internal use by buffer API functions */ +PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, + const Py_ssize_t *shape); +PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index, + const Py_ssize_t *shape); + + +#ifdef __cplusplus +} +#endif +#endif /* Py_ABSTRACTOBJECT_H */ diff --git a/libs/nxpy/include/accu.h b/libs/nxpy/include/accu.h index 3636ea6c..5856f117 100644 --- a/libs/nxpy/include/accu.h +++ b/libs/nxpy/include/accu.h @@ -1,37 +1,37 @@ -#ifndef Py_LIMITED_API -#ifndef Py_ACCU_H -#define Py_ACCU_H - -/*** This is a private API for use by the interpreter and the stdlib. - *** Its definition may be changed or removed at any moment. - ***/ - -/* - * A two-level accumulator of unicode objects that avoids both the overhead - * of keeping a huge number of small separate objects, and the quadratic - * behaviour of using a naive repeated concatenation scheme. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#undef small /* defined by some Windows headers */ - -typedef struct { - PyObject *large; /* A list of previously accumulated large strings */ - PyObject *small; /* Pending small strings */ -} _PyAccu; - -PyAPI_FUNC(int) _PyAccu_Init(_PyAccu *acc); -PyAPI_FUNC(int) _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode); -PyAPI_FUNC(PyObject *) _PyAccu_FinishAsList(_PyAccu *acc); -PyAPI_FUNC(PyObject *) _PyAccu_Finish(_PyAccu *acc); -PyAPI_FUNC(void) _PyAccu_Destroy(_PyAccu *acc); - -#ifdef __cplusplus -} -#endif - -#endif /* Py_ACCU_H */ -#endif /* Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_ACCU_H +#define Py_ACCU_H + +/*** This is a private API for use by the interpreter and the stdlib. + *** Its definition may be changed or removed at any moment. + ***/ + +/* + * A two-level accumulator of unicode objects that avoids both the overhead + * of keeping a huge number of small separate objects, and the quadratic + * behaviour of using a naive repeated concatenation scheme. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#undef small /* defined by some Windows headers */ + +typedef struct { + PyObject *large; /* A list of previously accumulated large strings */ + PyObject *small; /* Pending small strings */ +} _PyAccu; + +PyAPI_FUNC(int) _PyAccu_Init(_PyAccu *acc); +PyAPI_FUNC(int) _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode); +PyAPI_FUNC(PyObject *) _PyAccu_FinishAsList(_PyAccu *acc); +PyAPI_FUNC(PyObject *) _PyAccu_Finish(_PyAccu *acc); +PyAPI_FUNC(void) _PyAccu_Destroy(_PyAccu *acc); + +#ifdef __cplusplus +} +#endif + +#endif /* Py_ACCU_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/asdl.h b/libs/nxpy/include/asdl.h index 495153c5..256b9144 100644 --- a/libs/nxpy/include/asdl.h +++ b/libs/nxpy/include/asdl.h @@ -1,45 +1,45 @@ -#ifndef Py_ASDL_H -#define Py_ASDL_H - -typedef PyObject * identifier; -typedef PyObject * string; -typedef PyObject * bytes; -typedef PyObject * object; -typedef PyObject * singleton; - -/* It would be nice if the code generated by asdl_c.py was completely - independent of Python, but it is a goal the requires too much work - at this stage. So, for example, I'll represent identifiers as - interned Python strings. -*/ - -/* XXX A sequence should be typed so that its use can be typechecked. */ - -typedef struct { - Py_ssize_t size; - void *elements[1]; -} asdl_seq; - -typedef struct { - Py_ssize_t size; - int elements[1]; -} asdl_int_seq; - -asdl_seq *_Py_asdl_seq_new(Py_ssize_t size, PyArena *arena); -asdl_int_seq *_Py_asdl_int_seq_new(Py_ssize_t size, PyArena *arena); - -#define asdl_seq_GET(S, I) (S)->elements[(I)] -#define asdl_seq_LEN(S) ((S) == NULL ? 0 : (S)->size) -#ifdef Py_DEBUG -#define asdl_seq_SET(S, I, V) \ - do { \ - Py_ssize_t _asdl_i = (I); \ - assert((S) != NULL); \ - assert(_asdl_i < (S)->size); \ - (S)->elements[_asdl_i] = (V); \ - } while (0) -#else -#define asdl_seq_SET(S, I, V) (S)->elements[I] = (V) -#endif - -#endif /* !Py_ASDL_H */ +#ifndef Py_ASDL_H +#define Py_ASDL_H + +typedef PyObject * identifier; +typedef PyObject * string; +typedef PyObject * bytes; +typedef PyObject * object; +typedef PyObject * singleton; + +/* It would be nice if the code generated by asdl_c.py was completely + independent of Python, but it is a goal the requires too much work + at this stage. So, for example, I'll represent identifiers as + interned Python strings. +*/ + +/* XXX A sequence should be typed so that its use can be typechecked. */ + +typedef struct { + Py_ssize_t size; + void *elements[1]; +} asdl_seq; + +typedef struct { + Py_ssize_t size; + int elements[1]; +} asdl_int_seq; + +asdl_seq *_Py_asdl_seq_new(Py_ssize_t size, PyArena *arena); +asdl_int_seq *_Py_asdl_int_seq_new(Py_ssize_t size, PyArena *arena); + +#define asdl_seq_GET(S, I) (S)->elements[(I)] +#define asdl_seq_LEN(S) ((S) == NULL ? 0 : (S)->size) +#ifdef Py_DEBUG +#define asdl_seq_SET(S, I, V) \ + do { \ + Py_ssize_t _asdl_i = (I); \ + assert((S) != NULL); \ + assert(_asdl_i < (S)->size); \ + (S)->elements[_asdl_i] = (V); \ + } while (0) +#else +#define asdl_seq_SET(S, I, V) (S)->elements[I] = (V) +#endif + +#endif /* !Py_ASDL_H */ diff --git a/libs/nxpy/include/ast.h b/libs/nxpy/include/ast.h index 6a8c8165..25ea5fcf 100644 --- a/libs/nxpy/include/ast.h +++ b/libs/nxpy/include/ast.h @@ -1,22 +1,22 @@ -#ifndef Py_AST_H -#define Py_AST_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(int) PyAST_Validate(mod_ty); -PyAPI_FUNC(mod_ty) PyAST_FromNode( - const node *n, - PyCompilerFlags *flags, - const char *filename, /* decoded from the filesystem encoding */ - PyArena *arena); -PyAPI_FUNC(mod_ty) PyAST_FromNodeObject( - const node *n, - PyCompilerFlags *flags, - PyObject *filename, - PyArena *arena); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_AST_H */ +#ifndef Py_AST_H +#define Py_AST_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(int) PyAST_Validate(mod_ty); +PyAPI_FUNC(mod_ty) PyAST_FromNode( + const node *n, + PyCompilerFlags *flags, + const char *filename, /* decoded from the filesystem encoding */ + PyArena *arena); +PyAPI_FUNC(mod_ty) PyAST_FromNodeObject( + const node *n, + PyCompilerFlags *flags, + PyObject *filename, + PyArena *arena); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_AST_H */ diff --git a/libs/nxpy/include/bitset.h b/libs/nxpy/include/bitset.h index faeb4191..028acdf0 100644 --- a/libs/nxpy/include/bitset.h +++ b/libs/nxpy/include/bitset.h @@ -1,32 +1,32 @@ - -#ifndef Py_BITSET_H -#define Py_BITSET_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Bitset interface */ - -#define BYTE char - -typedef BYTE *bitset; - -bitset newbitset(int nbits); -void delbitset(bitset bs); -#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) -int addbit(bitset bs, int ibit); /* Returns 0 if already set */ -int samebitset(bitset bs1, bitset bs2, int nbits); -void mergebitset(bitset bs1, bitset bs2, int nbits); - -#define BITSPERBYTE (8*sizeof(BYTE)) -#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) - -#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) -#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) -#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) -#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BITSET_H */ + +#ifndef Py_BITSET_H +#define Py_BITSET_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Bitset interface */ + +#define BYTE char + +typedef BYTE *bitset; + +bitset newbitset(int nbits); +void delbitset(bitset bs); +#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) +int addbit(bitset bs, int ibit); /* Returns 0 if already set */ +int samebitset(bitset bs1, bitset bs2, int nbits); +void mergebitset(bitset bs1, bitset bs2, int nbits); + +#define BITSPERBYTE (8*sizeof(BYTE)) +#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) + +#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) +#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) +#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) +#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BITSET_H */ diff --git a/libs/nxpy/include/bltinmodule.h b/libs/nxpy/include/bltinmodule.h index 868c9e64..c04aceaa 100644 --- a/libs/nxpy/include/bltinmodule.h +++ b/libs/nxpy/include/bltinmodule.h @@ -1,14 +1,14 @@ -#ifndef Py_BLTINMODULE_H -#define Py_BLTINMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyFilter_Type; -PyAPI_DATA(PyTypeObject) PyMap_Type; -PyAPI_DATA(PyTypeObject) PyZip_Type; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BLTINMODULE_H */ +#ifndef Py_BLTINMODULE_H +#define Py_BLTINMODULE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyFilter_Type; +PyAPI_DATA(PyTypeObject) PyMap_Type; +PyAPI_DATA(PyTypeObject) PyZip_Type; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BLTINMODULE_H */ diff --git a/libs/nxpy/include/boolobject.h b/libs/nxpy/include/boolobject.h index 7cc2f1fe..79501fd9 100644 --- a/libs/nxpy/include/boolobject.h +++ b/libs/nxpy/include/boolobject.h @@ -1,34 +1,34 @@ -/* Boolean object interface */ - -#ifndef Py_BOOLOBJECT_H -#define Py_BOOLOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -PyAPI_DATA(PyTypeObject) PyBool_Type; - -#define PyBool_Check(x) (Py_TYPE(x) == &PyBool_Type) - -/* Py_False and Py_True are the only two bools in existence. -Don't forget to apply Py_INCREF() when returning either!!! */ - -/* Don't use these directly */ -PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct; - -/* Use these macros */ -#define Py_False ((PyObject *) &_Py_FalseStruct) -#define Py_True ((PyObject *) &_Py_TrueStruct) - -/* Macros for returning Py_True or Py_False, respectively */ -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False - -/* Function to return a bool from a C long */ -PyAPI_FUNC(PyObject *) PyBool_FromLong(long); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BOOLOBJECT_H */ +/* Boolean object interface */ + +#ifndef Py_BOOLOBJECT_H +#define Py_BOOLOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +PyAPI_DATA(PyTypeObject) PyBool_Type; + +#define PyBool_Check(x) (Py_TYPE(x) == &PyBool_Type) + +/* Py_False and Py_True are the only two bools in existence. +Don't forget to apply Py_INCREF() when returning either!!! */ + +/* Don't use these directly */ +PyAPI_DATA(struct _longobject) _Py_FalseStruct, _Py_TrueStruct; + +/* Use these macros */ +#define Py_False ((PyObject *) &_Py_FalseStruct) +#define Py_True ((PyObject *) &_Py_TrueStruct) + +/* Macros for returning Py_True or Py_False, respectively */ +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False + +/* Function to return a bool from a C long */ +PyAPI_FUNC(PyObject *) PyBool_FromLong(long); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BOOLOBJECT_H */ diff --git a/libs/nxpy/include/bytearrayobject.h b/libs/nxpy/include/bytearrayobject.h index a757b880..0d93e06b 100644 --- a/libs/nxpy/include/bytearrayobject.h +++ b/libs/nxpy/include/bytearrayobject.h @@ -1,62 +1,62 @@ -/* ByteArray object interface */ - -#ifndef Py_BYTEARRAYOBJECT_H -#define Py_BYTEARRAYOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Type PyByteArrayObject represents a mutable array of bytes. - * The Python API is that of a sequence; - * the bytes are mapped to ints in [0, 256). - * Bytes are not characters; they may be used to encode characters. - * The only way to go between bytes and str/unicode is via encoding - * and decoding. - * For the convenience of C programmers, the bytes type is considered - * to contain a char pointer, not an unsigned char pointer. - */ - -/* Object layout */ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_VAR_HEAD - Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */ - char *ob_bytes; /* Physical backing buffer */ - char *ob_start; /* Logical start inside ob_bytes */ - /* XXX(nnorwitz): should ob_exports be Py_ssize_t? */ - int ob_exports; /* How many buffer exports */ -} PyByteArrayObject; -#endif - -/* Type object */ -PyAPI_DATA(PyTypeObject) PyByteArray_Type; -PyAPI_DATA(PyTypeObject) PyByteArrayIter_Type; - -/* Type check macros */ -#define PyByteArray_Check(self) PyObject_TypeCheck(self, &PyByteArray_Type) -#define PyByteArray_CheckExact(self) (Py_TYPE(self) == &PyByteArray_Type) - -/* Direct API functions */ -PyAPI_FUNC(PyObject *) PyByteArray_FromObject(PyObject *); -PyAPI_FUNC(PyObject *) PyByteArray_Concat(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyByteArray_FromStringAndSize(const char *, Py_ssize_t); -PyAPI_FUNC(Py_ssize_t) PyByteArray_Size(PyObject *); -PyAPI_FUNC(char *) PyByteArray_AsString(PyObject *); -PyAPI_FUNC(int) PyByteArray_Resize(PyObject *, Py_ssize_t); - -/* Macros, trading safety for speed */ -#ifndef Py_LIMITED_API -#define PyByteArray_AS_STRING(self) \ - (assert(PyByteArray_Check(self)), \ - Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_start : _PyByteArray_empty_string) -#define PyByteArray_GET_SIZE(self) (assert(PyByteArray_Check(self)), Py_SIZE(self)) - -PyAPI_DATA(char) _PyByteArray_empty_string[]; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BYTEARRAYOBJECT_H */ +/* ByteArray object interface */ + +#ifndef Py_BYTEARRAYOBJECT_H +#define Py_BYTEARRAYOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Type PyByteArrayObject represents a mutable array of bytes. + * The Python API is that of a sequence; + * the bytes are mapped to ints in [0, 256). + * Bytes are not characters; they may be used to encode characters. + * The only way to go between bytes and str/unicode is via encoding + * and decoding. + * For the convenience of C programmers, the bytes type is considered + * to contain a char pointer, not an unsigned char pointer. + */ + +/* Object layout */ +#ifndef Py_LIMITED_API +typedef struct { + PyObject_VAR_HEAD + Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */ + char *ob_bytes; /* Physical backing buffer */ + char *ob_start; /* Logical start inside ob_bytes */ + /* XXX(nnorwitz): should ob_exports be Py_ssize_t? */ + int ob_exports; /* How many buffer exports */ +} PyByteArrayObject; +#endif + +/* Type object */ +PyAPI_DATA(PyTypeObject) PyByteArray_Type; +PyAPI_DATA(PyTypeObject) PyByteArrayIter_Type; + +/* Type check macros */ +#define PyByteArray_Check(self) PyObject_TypeCheck(self, &PyByteArray_Type) +#define PyByteArray_CheckExact(self) (Py_TYPE(self) == &PyByteArray_Type) + +/* Direct API functions */ +PyAPI_FUNC(PyObject *) PyByteArray_FromObject(PyObject *); +PyAPI_FUNC(PyObject *) PyByteArray_Concat(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyByteArray_FromStringAndSize(const char *, Py_ssize_t); +PyAPI_FUNC(Py_ssize_t) PyByteArray_Size(PyObject *); +PyAPI_FUNC(char *) PyByteArray_AsString(PyObject *); +PyAPI_FUNC(int) PyByteArray_Resize(PyObject *, Py_ssize_t); + +/* Macros, trading safety for speed */ +#ifndef Py_LIMITED_API +#define PyByteArray_AS_STRING(self) \ + (assert(PyByteArray_Check(self)), \ + Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_start : _PyByteArray_empty_string) +#define PyByteArray_GET_SIZE(self) (assert(PyByteArray_Check(self)), Py_SIZE(self)) + +PyAPI_DATA(char) _PyByteArray_empty_string[]; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BYTEARRAYOBJECT_H */ diff --git a/libs/nxpy/include/bytes_methods.h b/libs/nxpy/include/bytes_methods.h index 11d5f427..0ba41b43 100644 --- a/libs/nxpy/include/bytes_methods.h +++ b/libs/nxpy/include/bytes_methods.h @@ -1,46 +1,46 @@ -#ifndef Py_LIMITED_API -#ifndef Py_BYTES_CTYPE_H -#define Py_BYTES_CTYPE_H - -/* - * The internal implementation behind PyBytes (bytes) and PyByteArray (bytearray) - * methods of the given names, they operate on ASCII byte strings. - */ -extern PyObject* _Py_bytes_isspace(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isalpha(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isalnum(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isdigit(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_islower(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_isupper(const char *cptr, Py_ssize_t len); -extern PyObject* _Py_bytes_istitle(const char *cptr, Py_ssize_t len); - -/* These store their len sized answer in the given preallocated *result arg. */ -extern void _Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len); -extern void _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len); -extern void _Py_bytes_title(char *result, char *s, Py_ssize_t len); -extern void _Py_bytes_capitalize(char *result, char *s, Py_ssize_t len); -extern void _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len); - -/* The maketrans() static method. */ -extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); - -/* Shared __doc__ strings. */ -extern const char _Py_isspace__doc__[]; -extern const char _Py_isalpha__doc__[]; -extern const char _Py_isalnum__doc__[]; -extern const char _Py_isdigit__doc__[]; -extern const char _Py_islower__doc__[]; -extern const char _Py_isupper__doc__[]; -extern const char _Py_istitle__doc__[]; -extern const char _Py_lower__doc__[]; -extern const char _Py_upper__doc__[]; -extern const char _Py_title__doc__[]; -extern const char _Py_capitalize__doc__[]; -extern const char _Py_swapcase__doc__[]; -extern const char _Py_maketrans__doc__[]; - -/* this is needed because some docs are shared from the .o, not static */ -#define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str) - -#endif /* !Py_BYTES_CTYPE_H */ -#endif /* !Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_BYTES_CTYPE_H +#define Py_BYTES_CTYPE_H + +/* + * The internal implementation behind PyBytes (bytes) and PyByteArray (bytearray) + * methods of the given names, they operate on ASCII byte strings. + */ +extern PyObject* _Py_bytes_isspace(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_isalpha(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_isalnum(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_isdigit(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_islower(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_isupper(const char *cptr, Py_ssize_t len); +extern PyObject* _Py_bytes_istitle(const char *cptr, Py_ssize_t len); + +/* These store their len sized answer in the given preallocated *result arg. */ +extern void _Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len); +extern void _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len); +extern void _Py_bytes_title(char *result, char *s, Py_ssize_t len); +extern void _Py_bytes_capitalize(char *result, char *s, Py_ssize_t len); +extern void _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len); + +/* The maketrans() static method. */ +extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); + +/* Shared __doc__ strings. */ +extern const char _Py_isspace__doc__[]; +extern const char _Py_isalpha__doc__[]; +extern const char _Py_isalnum__doc__[]; +extern const char _Py_isdigit__doc__[]; +extern const char _Py_islower__doc__[]; +extern const char _Py_isupper__doc__[]; +extern const char _Py_istitle__doc__[]; +extern const char _Py_lower__doc__[]; +extern const char _Py_upper__doc__[]; +extern const char _Py_title__doc__[]; +extern const char _Py_capitalize__doc__[]; +extern const char _Py_swapcase__doc__[]; +extern const char _Py_maketrans__doc__[]; + +/* this is needed because some docs are shared from the .o, not static */ +#define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str) + +#endif /* !Py_BYTES_CTYPE_H */ +#endif /* !Py_LIMITED_API */ diff --git a/libs/nxpy/include/bytesobject.h b/libs/nxpy/include/bytesobject.h index 6c1e0c3a..520bfe03 100644 --- a/libs/nxpy/include/bytesobject.h +++ b/libs/nxpy/include/bytesobject.h @@ -1,129 +1,129 @@ - -/* Bytes (String) object interface */ - -#ifndef Py_BYTESOBJECT_H -#define Py_BYTESOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* -Type PyBytesObject represents a character string. An extra zero byte is -reserved at the end to ensure it is zero-terminated, but a size is -present so strings with null bytes in them can be represented. This -is an immutable object type. - -There are functions to create new string objects, to test -an object for string-ness, and to get the -string value. The latter function returns a null pointer -if the object is not of the proper type. -There is a variant that takes an explicit size as well as a -variant that assumes a zero-terminated string. Note that none of the -functions should be applied to nil objects. -*/ - -/* Caching the hash (ob_shash) saves recalculation of a string's hash value. - This significantly speeds up dict lookups. */ - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_VAR_HEAD - Py_hash_t ob_shash; - char ob_sval[1]; - - /* Invariants: - * ob_sval contains space for 'ob_size+1' elements. - * ob_sval[ob_size] == 0. - * ob_shash is the hash of the string or -1 if not computed yet. - */ -} PyBytesObject; -#endif - -PyAPI_DATA(PyTypeObject) PyBytes_Type; -PyAPI_DATA(PyTypeObject) PyBytesIter_Type; - -#define PyBytes_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS) -#define PyBytes_CheckExact(op) (Py_TYPE(op) == &PyBytes_Type) - -PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t); -PyAPI_FUNC(PyObject *) PyBytes_FromString(const char *); -PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *); -PyAPI_FUNC(PyObject *) PyBytes_FromFormatV(const char*, va_list) - Py_GCC_ATTRIBUTE((format(printf, 1, 0))); -PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *); -PyAPI_FUNC(char *) PyBytes_AsString(PyObject *); -PyAPI_FUNC(PyObject *) PyBytes_Repr(PyObject *, int); -PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *); -PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t); -PyAPI_FUNC(PyObject *) _PyBytes_Format(PyObject *, PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t, - const char *, Py_ssize_t, - const char *); - -/* Macro, trading safety for speed */ -#ifndef Py_LIMITED_API -#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \ - (((PyBytesObject *)(op))->ob_sval)) -#define PyBytes_GET_SIZE(op) (assert(PyBytes_Check(op)),Py_SIZE(op)) -#endif - -/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*, - x must be an iterable object. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyBytes_Join(PyObject *sep, PyObject *x); -#endif - -/* Provides access to the internal data buffer and size of a string - object or the default encoded version of a Unicode object. Passing - NULL as *len parameter will force the string buffer to be - 0-terminated (passing a string with embedded NULL characters will - cause an exception). */ -PyAPI_FUNC(int) PyBytes_AsStringAndSize( - PyObject *obj, /* string or Unicode object */ - char **s, /* pointer to buffer variable */ - Py_ssize_t *len /* pointer to length variable or NULL - (only possible for 0-terminated - strings) */ - ); - -/* Using the current locale, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyBytes_InsertThousandsGroupingLocale(char *buffer, - Py_ssize_t n_buffer, - char *digits, - Py_ssize_t n_digits, - Py_ssize_t min_width); - -/* Using explicit passed-in values, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -PyAPI_FUNC(Py_ssize_t) _PyBytes_InsertThousandsGrouping(char *buffer, - Py_ssize_t n_buffer, - char *digits, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - const char *thousands_sep); -#endif - -/* Flags used by string formatting */ -#define F_LJUST (1<<0) -#define F_SIGN (1<<1) -#define F_BLANK (1<<2) -#define F_ALT (1<<3) -#define F_ZERO (1<<4) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_BYTESOBJECT_H */ + +/* Bytes (String) object interface */ + +#ifndef Py_BYTESOBJECT_H +#define Py_BYTESOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* +Type PyBytesObject represents a character string. An extra zero byte is +reserved at the end to ensure it is zero-terminated, but a size is +present so strings with null bytes in them can be represented. This +is an immutable object type. + +There are functions to create new string objects, to test +an object for string-ness, and to get the +string value. The latter function returns a null pointer +if the object is not of the proper type. +There is a variant that takes an explicit size as well as a +variant that assumes a zero-terminated string. Note that none of the +functions should be applied to nil objects. +*/ + +/* Caching the hash (ob_shash) saves recalculation of a string's hash value. + This significantly speeds up dict lookups. */ + +#ifndef Py_LIMITED_API +typedef struct { + PyObject_VAR_HEAD + Py_hash_t ob_shash; + char ob_sval[1]; + + /* Invariants: + * ob_sval contains space for 'ob_size+1' elements. + * ob_sval[ob_size] == 0. + * ob_shash is the hash of the string or -1 if not computed yet. + */ +} PyBytesObject; +#endif + +PyAPI_DATA(PyTypeObject) PyBytes_Type; +PyAPI_DATA(PyTypeObject) PyBytesIter_Type; + +#define PyBytes_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS) +#define PyBytes_CheckExact(op) (Py_TYPE(op) == &PyBytes_Type) + +PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t); +PyAPI_FUNC(PyObject *) PyBytes_FromString(const char *); +PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *); +PyAPI_FUNC(PyObject *) PyBytes_FromFormatV(const char*, va_list) + Py_GCC_ATTRIBUTE((format(printf, 1, 0))); +PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *); +PyAPI_FUNC(char *) PyBytes_AsString(PyObject *); +PyAPI_FUNC(PyObject *) PyBytes_Repr(PyObject *, int); +PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *); +PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t); +PyAPI_FUNC(PyObject *) _PyBytes_Format(PyObject *, PyObject *); +#endif +PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t, + const char *, Py_ssize_t, + const char *); + +/* Macro, trading safety for speed */ +#ifndef Py_LIMITED_API +#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \ + (((PyBytesObject *)(op))->ob_sval)) +#define PyBytes_GET_SIZE(op) (assert(PyBytes_Check(op)),Py_SIZE(op)) +#endif + +/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*, + x must be an iterable object. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyBytes_Join(PyObject *sep, PyObject *x); +#endif + +/* Provides access to the internal data buffer and size of a string + object or the default encoded version of a Unicode object. Passing + NULL as *len parameter will force the string buffer to be + 0-terminated (passing a string with embedded NULL characters will + cause an exception). */ +PyAPI_FUNC(int) PyBytes_AsStringAndSize( + PyObject *obj, /* string or Unicode object */ + char **s, /* pointer to buffer variable */ + Py_ssize_t *len /* pointer to length variable or NULL + (only possible for 0-terminated + strings) */ + ); + +/* Using the current locale, insert the thousands grouping + into the string pointed to by buffer. For the argument descriptions, + see Objects/stringlib/localeutil.h */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyBytes_InsertThousandsGroupingLocale(char *buffer, + Py_ssize_t n_buffer, + char *digits, + Py_ssize_t n_digits, + Py_ssize_t min_width); + +/* Using explicit passed-in values, insert the thousands grouping + into the string pointed to by buffer. For the argument descriptions, + see Objects/stringlib/localeutil.h */ +PyAPI_FUNC(Py_ssize_t) _PyBytes_InsertThousandsGrouping(char *buffer, + Py_ssize_t n_buffer, + char *digits, + Py_ssize_t n_digits, + Py_ssize_t min_width, + const char *grouping, + const char *thousands_sep); +#endif + +/* Flags used by string formatting */ +#define F_LJUST (1<<0) +#define F_SIGN (1<<1) +#define F_BLANK (1<<2) +#define F_ALT (1<<3) +#define F_ZERO (1<<4) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BYTESOBJECT_H */ diff --git a/libs/nxpy/include/cellobject.h b/libs/nxpy/include/cellobject.h index a0aa4d94..36f259e2 100644 --- a/libs/nxpy/include/cellobject.h +++ b/libs/nxpy/include/cellobject.h @@ -1,29 +1,29 @@ -/* Cell object interface */ -#ifndef Py_LIMITED_API -#ifndef Py_CELLOBJECT_H -#define Py_CELLOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_HEAD - PyObject *ob_ref; /* Content of the cell or NULL when empty */ -} PyCellObject; - -PyAPI_DATA(PyTypeObject) PyCell_Type; - -#define PyCell_Check(op) (Py_TYPE(op) == &PyCell_Type) - -PyAPI_FUNC(PyObject *) PyCell_New(PyObject *); -PyAPI_FUNC(PyObject *) PyCell_Get(PyObject *); -PyAPI_FUNC(int) PyCell_Set(PyObject *, PyObject *); - -#define PyCell_GET(op) (((PyCellObject *)(op))->ob_ref) -#define PyCell_SET(op, v) (((PyCellObject *)(op))->ob_ref = v) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TUPLEOBJECT_H */ -#endif /* Py_LIMITED_API */ +/* Cell object interface */ +#ifndef Py_LIMITED_API +#ifndef Py_CELLOBJECT_H +#define Py_CELLOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + PyObject *ob_ref; /* Content of the cell or NULL when empty */ +} PyCellObject; + +PyAPI_DATA(PyTypeObject) PyCell_Type; + +#define PyCell_Check(op) (Py_TYPE(op) == &PyCell_Type) + +PyAPI_FUNC(PyObject *) PyCell_New(PyObject *); +PyAPI_FUNC(PyObject *) PyCell_Get(PyObject *); +PyAPI_FUNC(int) PyCell_Set(PyObject *, PyObject *); + +#define PyCell_GET(op) (((PyCellObject *)(op))->ob_ref) +#define PyCell_SET(op, v) (((PyCellObject *)(op))->ob_ref = v) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TUPLEOBJECT_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/ceval.h b/libs/nxpy/include/ceval.h index b5373a9c..7bdd1d44 100644 --- a/libs/nxpy/include/ceval.h +++ b/libs/nxpy/include/ceval.h @@ -1,213 +1,213 @@ -#ifndef Py_CEVAL_H -#define Py_CEVAL_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Interface to random parts in ceval.c */ - -PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( - PyObject *, PyObject *, PyObject *); - -/* Inline this */ -#define PyEval_CallObject(func,arg) \ - PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) - -PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *obj, - const char *format, ...); -PyAPI_FUNC(PyObject *) PyEval_CallMethod(PyObject *obj, - const char *methodname, - const char *format, ...); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); -PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); -PyAPI_FUNC(void) _PyEval_SetCoroutineWrapper(PyObject *); -PyAPI_FUNC(PyObject *) _PyEval_GetCoroutineWrapper(void); -#endif - -struct _frame; /* Avoid including frameobject.h */ - -PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void); -PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void); -PyAPI_FUNC(PyObject *) PyEval_GetLocals(void); -PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void); - -/* Look at the current frame's (if any) code's co_flags, and turn on - the corresponding compiler flags in cf->cf_flags. Return 1 if any - flag was set, else return 0. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); -#endif - -PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg); -PyAPI_FUNC(int) Py_MakePendingCalls(void); - -/* Protection against deeply nested recursive calls - - In Python 3.0, this protection has two levels: - * normal anti-recursion protection is triggered when the recursion level - exceeds the current recursion limit. It raises a RecursionError, and sets - the "overflowed" flag in the thread state structure. This flag - temporarily *disables* the normal protection; this allows cleanup code - to potentially outgrow the recursion limit while processing the - RecursionError. - * "last chance" anti-recursion protection is triggered when the recursion - level exceeds "current recursion limit + 50". By construction, this - protection can only be triggered when the "overflowed" flag is set. It - means the cleanup code has itself gone into an infinite loop, or the - RecursionError has been mistakingly ignored. When this protection is - triggered, the interpreter aborts with a Fatal Error. - - In addition, the "overflowed" flag is automatically reset when the - recursion level drops below "current recursion limit - 50". This heuristic - is meant to ensure that the normal anti-recursion protection doesn't get - disabled too long. - - Please note: this scheme has its own limitations. See: - http://mail.python.org/pipermail/python-dev/2008-August/082106.html - for some observations. -*/ -PyAPI_FUNC(void) Py_SetRecursionLimit(int); -PyAPI_FUNC(int) Py_GetRecursionLimit(void); - -#define Py_EnterRecursiveCall(where) \ - (_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \ - _Py_CheckRecursiveCall(where)) -#define Py_LeaveRecursiveCall() \ - do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \ - PyThreadState_GET()->overflowed = 0; \ - } while(0) -PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where); -PyAPI_DATA(int) _Py_CheckRecursionLimit; - -#ifdef USE_STACKCHECK -/* With USE_STACKCHECK, we artificially decrement the recursion limit in order - to trigger regular stack checks in _Py_CheckRecursiveCall(), except if - the "overflowed" flag is set, in which case we need the true value - of _Py_CheckRecursionLimit for _Py_MakeEndRecCheck() to function properly. -*/ -# define _Py_MakeRecCheck(x) \ - (++(x) > (_Py_CheckRecursionLimit += PyThreadState_GET()->overflowed - 1)) -#else -# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) -#endif - -/* Compute the "lower-water mark" for a recursion limit. When - * Py_LeaveRecursiveCall() is called with a recursion depth below this mark, - * the overflowed flag is reset to 0. */ -#define _Py_RecursionLimitLowerWaterMark(limit) \ - (((limit) > 200) \ - ? ((limit) - 50) \ - : (3 * ((limit) >> 2))) - -#define _Py_MakeEndRecCheck(x) \ - (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) - -#define Py_ALLOW_RECURSION \ - do { unsigned char _old = PyThreadState_GET()->recursion_critical;\ - PyThreadState_GET()->recursion_critical = 1; - -#define Py_END_ALLOW_RECURSION \ - PyThreadState_GET()->recursion_critical = _old; \ - } while(0); - -PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *); -PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *); - -PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *); -PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *); -PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc); - -/* Interface for threads. - - A module that plans to do a blocking system call (or something else - that lasts a long time and doesn't touch Python data) can allow other - threads to run as follows: - - ...preparations here... - Py_BEGIN_ALLOW_THREADS - ...blocking system call here... - Py_END_ALLOW_THREADS - ...interpret result here... - - The Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS pair expands to a - {}-surrounded block. - To leave the block in the middle (e.g., with return), you must insert - a line containing Py_BLOCK_THREADS before the return, e.g. - - if (...premature_exit...) { - Py_BLOCK_THREADS - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - An alternative is: - - Py_BLOCK_THREADS - if (...premature_exit...) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - Py_UNBLOCK_THREADS - - For convenience, that the value of 'errno' is restored across - Py_END_ALLOW_THREADS and Py_BLOCK_THREADS. - - WARNING: NEVER NEST CALLS TO Py_BEGIN_ALLOW_THREADS AND - Py_END_ALLOW_THREADS!!! - - The function PyEval_InitThreads() should be called only from - init_thread() in "_threadmodule.c". - - Note that not yet all candidates have been converted to use this - mechanism! -*/ - -PyAPI_FUNC(PyThreadState *) PyEval_SaveThread(void); -PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *); - -#ifdef WITH_THREAD - -PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); -PyAPI_FUNC(void) PyEval_InitThreads(void); -PyAPI_FUNC(void) _PyEval_FiniThreads(void); -PyAPI_FUNC(void) PyEval_AcquireLock(void); -PyAPI_FUNC(void) PyEval_ReleaseLock(void); -PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate); -PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate); -PyAPI_FUNC(void) PyEval_ReInitThreads(void); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); -PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); -#endif - -#define Py_BEGIN_ALLOW_THREADS { \ - PyThreadState *_save; \ - _save = PyEval_SaveThread(); -#define Py_BLOCK_THREADS PyEval_RestoreThread(_save); -#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); -#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \ - } - -#else /* !WITH_THREAD */ - -#define Py_BEGIN_ALLOW_THREADS { -#define Py_BLOCK_THREADS -#define Py_UNBLOCK_THREADS -#define Py_END_ALLOW_THREADS } - -#endif /* !WITH_THREAD */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); -PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void); -#endif - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CEVAL_H */ +#ifndef Py_CEVAL_H +#define Py_CEVAL_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Interface to random parts in ceval.c */ + +PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( + PyObject *, PyObject *, PyObject *); + +/* Inline this */ +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *obj, + const char *format, ...); +PyAPI_FUNC(PyObject *) PyEval_CallMethod(PyObject *obj, + const char *methodname, + const char *format, ...); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); +PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); +PyAPI_FUNC(void) _PyEval_SetCoroutineWrapper(PyObject *); +PyAPI_FUNC(PyObject *) _PyEval_GetCoroutineWrapper(void); +#endif + +struct _frame; /* Avoid including frameobject.h */ + +PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void); +PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void); +PyAPI_FUNC(PyObject *) PyEval_GetLocals(void); +PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void); + +/* Look at the current frame's (if any) code's co_flags, and turn on + the corresponding compiler flags in cf->cf_flags. Return 1 if any + flag was set, else return 0. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); +#endif + +PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg); +PyAPI_FUNC(int) Py_MakePendingCalls(void); + +/* Protection against deeply nested recursive calls + + In Python 3.0, this protection has two levels: + * normal anti-recursion protection is triggered when the recursion level + exceeds the current recursion limit. It raises a RecursionError, and sets + the "overflowed" flag in the thread state structure. This flag + temporarily *disables* the normal protection; this allows cleanup code + to potentially outgrow the recursion limit while processing the + RecursionError. + * "last chance" anti-recursion protection is triggered when the recursion + level exceeds "current recursion limit + 50". By construction, this + protection can only be triggered when the "overflowed" flag is set. It + means the cleanup code has itself gone into an infinite loop, or the + RecursionError has been mistakingly ignored. When this protection is + triggered, the interpreter aborts with a Fatal Error. + + In addition, the "overflowed" flag is automatically reset when the + recursion level drops below "current recursion limit - 50". This heuristic + is meant to ensure that the normal anti-recursion protection doesn't get + disabled too long. + + Please note: this scheme has its own limitations. See: + http://mail.python.org/pipermail/python-dev/2008-August/082106.html + for some observations. +*/ +PyAPI_FUNC(void) Py_SetRecursionLimit(int); +PyAPI_FUNC(int) Py_GetRecursionLimit(void); + +#define Py_EnterRecursiveCall(where) \ + (_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \ + _Py_CheckRecursiveCall(where)) +#define Py_LeaveRecursiveCall() \ + do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \ + PyThreadState_GET()->overflowed = 0; \ + } while(0) +PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where); +PyAPI_DATA(int) _Py_CheckRecursionLimit; + +#ifdef USE_STACKCHECK +/* With USE_STACKCHECK, we artificially decrement the recursion limit in order + to trigger regular stack checks in _Py_CheckRecursiveCall(), except if + the "overflowed" flag is set, in which case we need the true value + of _Py_CheckRecursionLimit for _Py_MakeEndRecCheck() to function properly. +*/ +# define _Py_MakeRecCheck(x) \ + (++(x) > (_Py_CheckRecursionLimit += PyThreadState_GET()->overflowed - 1)) +#else +# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) +#endif + +/* Compute the "lower-water mark" for a recursion limit. When + * Py_LeaveRecursiveCall() is called with a recursion depth below this mark, + * the overflowed flag is reset to 0. */ +#define _Py_RecursionLimitLowerWaterMark(limit) \ + (((limit) > 200) \ + ? ((limit) - 50) \ + : (3 * ((limit) >> 2))) + +#define _Py_MakeEndRecCheck(x) \ + (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit)) + +#define Py_ALLOW_RECURSION \ + do { unsigned char _old = PyThreadState_GET()->recursion_critical;\ + PyThreadState_GET()->recursion_critical = 1; + +#define Py_END_ALLOW_RECURSION \ + PyThreadState_GET()->recursion_critical = _old; \ + } while(0); + +PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *); +PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *); + +PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *); +PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *); +PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc); + +/* Interface for threads. + + A module that plans to do a blocking system call (or something else + that lasts a long time and doesn't touch Python data) can allow other + threads to run as follows: + + ...preparations here... + Py_BEGIN_ALLOW_THREADS + ...blocking system call here... + Py_END_ALLOW_THREADS + ...interpret result here... + + The Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS pair expands to a + {}-surrounded block. + To leave the block in the middle (e.g., with return), you must insert + a line containing Py_BLOCK_THREADS before the return, e.g. + + if (...premature_exit...) { + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + An alternative is: + + Py_BLOCK_THREADS + if (...premature_exit...) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_UNBLOCK_THREADS + + For convenience, that the value of 'errno' is restored across + Py_END_ALLOW_THREADS and Py_BLOCK_THREADS. + + WARNING: NEVER NEST CALLS TO Py_BEGIN_ALLOW_THREADS AND + Py_END_ALLOW_THREADS!!! + + The function PyEval_InitThreads() should be called only from + init_thread() in "_threadmodule.c". + + Note that not yet all candidates have been converted to use this + mechanism! +*/ + +PyAPI_FUNC(PyThreadState *) PyEval_SaveThread(void); +PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *); + +#ifdef WITH_THREAD + +PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); +PyAPI_FUNC(void) PyEval_InitThreads(void); +PyAPI_FUNC(void) _PyEval_FiniThreads(void); +PyAPI_FUNC(void) PyEval_AcquireLock(void); +PyAPI_FUNC(void) PyEval_ReleaseLock(void); +PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate); +PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate); +PyAPI_FUNC(void) PyEval_ReInitThreads(void); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); +PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); +#endif + +#define Py_BEGIN_ALLOW_THREADS { \ + PyThreadState *_save; \ + _save = PyEval_SaveThread(); +#define Py_BLOCK_THREADS PyEval_RestoreThread(_save); +#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); +#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \ + } + +#else /* !WITH_THREAD */ + +#define Py_BEGIN_ALLOW_THREADS { +#define Py_BLOCK_THREADS +#define Py_UNBLOCK_THREADS +#define Py_END_ALLOW_THREADS } + +#endif /* !WITH_THREAD */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); +PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void); +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CEVAL_H */ diff --git a/libs/nxpy/include/classobject.h b/libs/nxpy/include/classobject.h index eeeb3e95..1ccb86d0 100644 --- a/libs/nxpy/include/classobject.h +++ b/libs/nxpy/include/classobject.h @@ -1,58 +1,58 @@ -/* Former class object interface -- now only bound methods are here */ - -/* Revealing some structures (not for general use) */ - -#ifndef Py_LIMITED_API -#ifndef Py_CLASSOBJECT_H -#define Py_CLASSOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PyObject_HEAD - PyObject *im_func; /* The callable object implementing the method */ - PyObject *im_self; /* The instance it is bound to */ - PyObject *im_weakreflist; /* List of weak references */ -} PyMethodObject; - -PyAPI_DATA(PyTypeObject) PyMethod_Type; - -#define PyMethod_Check(op) ((op)->ob_type == &PyMethod_Type) - -PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); -PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyMethod_GET_FUNCTION(meth) \ - (((PyMethodObject *)meth) -> im_func) -#define PyMethod_GET_SELF(meth) \ - (((PyMethodObject *)meth) -> im_self) - -PyAPI_FUNC(int) PyMethod_ClearFreeList(void); - -typedef struct { - PyObject_HEAD - PyObject *func; -} PyInstanceMethodObject; - -PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type; - -#define PyInstanceMethod_Check(op) ((op)->ob_type == &PyInstanceMethod_Type) - -PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *); -PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyInstanceMethod_GET_FUNCTION(meth) \ - (((PyInstanceMethodObject *)meth) -> func) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CLASSOBJECT_H */ -#endif /* Py_LIMITED_API */ +/* Former class object interface -- now only bound methods are here */ + +/* Revealing some structures (not for general use) */ + +#ifndef Py_LIMITED_API +#ifndef Py_CLASSOBJECT_H +#define Py_CLASSOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + PyObject *im_func; /* The callable object implementing the method */ + PyObject *im_self; /* The instance it is bound to */ + PyObject *im_weakreflist; /* List of weak references */ +} PyMethodObject; + +PyAPI_DATA(PyTypeObject) PyMethod_Type; + +#define PyMethod_Check(op) ((op)->ob_type == &PyMethod_Type) + +PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *); + +PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); +PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyMethod_GET_FUNCTION(meth) \ + (((PyMethodObject *)meth) -> im_func) +#define PyMethod_GET_SELF(meth) \ + (((PyMethodObject *)meth) -> im_self) + +PyAPI_FUNC(int) PyMethod_ClearFreeList(void); + +typedef struct { + PyObject_HEAD + PyObject *func; +} PyInstanceMethodObject; + +PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type; + +#define PyInstanceMethod_Check(op) ((op)->ob_type == &PyInstanceMethod_Type) + +PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *); +PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyInstanceMethod_GET_FUNCTION(meth) \ + (((PyInstanceMethodObject *)meth) -> func) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CLASSOBJECT_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/code.h b/libs/nxpy/include/code.h index 8ecf38a3..3f679262 100644 --- a/libs/nxpy/include/code.h +++ b/libs/nxpy/include/code.h @@ -1,135 +1,135 @@ -/* Definitions for bytecode */ - -#ifndef Py_LIMITED_API -#ifndef Py_CODE_H -#define Py_CODE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Bytecode object */ -typedef struct { - PyObject_HEAD - int co_argcount; /* #arguments, except *args */ - int co_kwonlyargcount; /* #keyword only arguments */ - int co_nlocals; /* #local variables */ - int co_stacksize; /* #entries needed for evaluation stack */ - int co_flags; /* CO_..., see below */ - PyObject *co_code; /* instruction opcodes */ - PyObject *co_consts; /* list (constants used) */ - PyObject *co_names; /* list of strings (names used) */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - /* The rest aren't used in either hash or comparisons, except for - co_name (used in both) and co_firstlineno (used only in - comparisons). This is done to preserve the name and line number - for tracebacks and debuggers; otherwise, constant de-duplication - would collapse identical functions/lambdas defined on different lines. - */ - unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ - PyObject *co_filename; /* unicode (where it was loaded from) */ - PyObject *co_name; /* unicode (name, for reference) */ - int co_firstlineno; /* first source line number */ - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See - Objects/lnotab_notes.txt for details. */ - void *co_zombieframe; /* for optimization only (see frameobject.c) */ - PyObject *co_weakreflist; /* to support weakrefs to code objects */ -} PyCodeObject; - -/* Masks for co_flags above */ -#define CO_OPTIMIZED 0x0001 -#define CO_NEWLOCALS 0x0002 -#define CO_VARARGS 0x0004 -#define CO_VARKEYWORDS 0x0008 -#define CO_NESTED 0x0010 -#define CO_GENERATOR 0x0020 -/* The CO_NOFREE flag is set if there are no free or cell variables. - This information is redundant, but it allows a single flag test - to determine whether there is any extra work to be done when the - call frame it setup. -*/ -#define CO_NOFREE 0x0040 - -/* The CO_COROUTINE flag is set for coroutine functions (defined with - ``async def`` keywords) */ -#define CO_COROUTINE 0x0080 -#define CO_ITERABLE_COROUTINE 0x0100 - -/* These are no longer used. */ -#if 0 -#define CO_GENERATOR_ALLOWED 0x1000 -#endif -#define CO_FUTURE_DIVISION 0x2000 -#define CO_FUTURE_ABSOLUTE_IMPORT 0x4000 /* do absolute imports by default */ -#define CO_FUTURE_WITH_STATEMENT 0x8000 -#define CO_FUTURE_PRINT_FUNCTION 0x10000 -#define CO_FUTURE_UNICODE_LITERALS 0x20000 - -#define CO_FUTURE_BARRY_AS_BDFL 0x40000 -#define CO_FUTURE_GENERATOR_STOP 0x80000 - -/* This value is found in the co_cell2arg array when the associated cell - variable does not correspond to an argument. The maximum number of - arguments is 255 (indexed up to 254), so 255 work as a special flag.*/ -#define CO_CELL_NOT_AN_ARG 255 - -/* This should be defined if a future statement modifies the syntax. - For example, when a keyword is added. -*/ -#define PY_PARSER_REQUIRES_FUTURE_KEYWORD - -#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */ - -PyAPI_DATA(PyTypeObject) PyCode_Type; - -#define PyCode_Check(op) (Py_TYPE(op) == &PyCode_Type) -#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars)) - -/* Public interface */ -PyAPI_FUNC(PyCodeObject *) PyCode_New( - int, int, int, int, int, PyObject *, PyObject *, - PyObject *, PyObject *, PyObject *, PyObject *, - PyObject *, PyObject *, int, PyObject *); - /* same as struct above */ - -/* Creates a new empty code object with the specified source location. */ -PyAPI_FUNC(PyCodeObject *) -PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno); - -/* Return the line number associated with the specified bytecode index - in this code object. If you just need the line number of a frame, - use PyFrame_GetLineNumber() instead. */ -PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); - -/* for internal use only */ -typedef struct _addr_pair { - int ap_lower; - int ap_upper; -} PyAddrPair; - -#ifndef Py_LIMITED_API -/* Update *bounds to describe the first and one-past-the-last instructions in the - same line as lasti. Return the number of that line. -*/ -PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co, - int lasti, PyAddrPair *bounds); - -/* Create a comparable key used to compare constants taking in account the - * object type. It is used to make sure types are not coerced (e.g., float and - * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms - * - * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items) - * depending on the type and the value. The type is the first item to not - * compare bytes and str which can raise a BytesWarning exception. */ -PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj); -#endif - -PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, - PyObject *names, PyObject *lineno_obj); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CODE_H */ -#endif /* Py_LIMITED_API */ +/* Definitions for bytecode */ + +#ifndef Py_LIMITED_API +#ifndef Py_CODE_H +#define Py_CODE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Bytecode object */ +typedef struct { + PyObject_HEAD + int co_argcount; /* #arguments, except *args */ + int co_kwonlyargcount; /* #keyword only arguments */ + int co_nlocals; /* #local variables */ + int co_stacksize; /* #entries needed for evaluation stack */ + int co_flags; /* CO_..., see below */ + PyObject *co_code; /* instruction opcodes */ + PyObject *co_consts; /* list (constants used) */ + PyObject *co_names; /* list of strings (names used) */ + PyObject *co_varnames; /* tuple of strings (local variable names) */ + PyObject *co_freevars; /* tuple of strings (free variable names) */ + PyObject *co_cellvars; /* tuple of strings (cell variable names) */ + /* The rest aren't used in either hash or comparisons, except for + co_name (used in both) and co_firstlineno (used only in + comparisons). This is done to preserve the name and line number + for tracebacks and debuggers; otherwise, constant de-duplication + would collapse identical functions/lambdas defined on different lines. + */ + unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ + PyObject *co_filename; /* unicode (where it was loaded from) */ + PyObject *co_name; /* unicode (name, for reference) */ + int co_firstlineno; /* first source line number */ + PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See + Objects/lnotab_notes.txt for details. */ + void *co_zombieframe; /* for optimization only (see frameobject.c) */ + PyObject *co_weakreflist; /* to support weakrefs to code objects */ +} PyCodeObject; + +/* Masks for co_flags above */ +#define CO_OPTIMIZED 0x0001 +#define CO_NEWLOCALS 0x0002 +#define CO_VARARGS 0x0004 +#define CO_VARKEYWORDS 0x0008 +#define CO_NESTED 0x0010 +#define CO_GENERATOR 0x0020 +/* The CO_NOFREE flag is set if there are no free or cell variables. + This information is redundant, but it allows a single flag test + to determine whether there is any extra work to be done when the + call frame it setup. +*/ +#define CO_NOFREE 0x0040 + +/* The CO_COROUTINE flag is set for coroutine functions (defined with + ``async def`` keywords) */ +#define CO_COROUTINE 0x0080 +#define CO_ITERABLE_COROUTINE 0x0100 + +/* These are no longer used. */ +#if 0 +#define CO_GENERATOR_ALLOWED 0x1000 +#endif +#define CO_FUTURE_DIVISION 0x2000 +#define CO_FUTURE_ABSOLUTE_IMPORT 0x4000 /* do absolute imports by default */ +#define CO_FUTURE_WITH_STATEMENT 0x8000 +#define CO_FUTURE_PRINT_FUNCTION 0x10000 +#define CO_FUTURE_UNICODE_LITERALS 0x20000 + +#define CO_FUTURE_BARRY_AS_BDFL 0x40000 +#define CO_FUTURE_GENERATOR_STOP 0x80000 + +/* This value is found in the co_cell2arg array when the associated cell + variable does not correspond to an argument. The maximum number of + arguments is 255 (indexed up to 254), so 255 work as a special flag.*/ +#define CO_CELL_NOT_AN_ARG 255 + +/* This should be defined if a future statement modifies the syntax. + For example, when a keyword is added. +*/ +#define PY_PARSER_REQUIRES_FUTURE_KEYWORD + +#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */ + +PyAPI_DATA(PyTypeObject) PyCode_Type; + +#define PyCode_Check(op) (Py_TYPE(op) == &PyCode_Type) +#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars)) + +/* Public interface */ +PyAPI_FUNC(PyCodeObject *) PyCode_New( + int, int, int, int, int, PyObject *, PyObject *, + PyObject *, PyObject *, PyObject *, PyObject *, + PyObject *, PyObject *, int, PyObject *); + /* same as struct above */ + +/* Creates a new empty code object with the specified source location. */ +PyAPI_FUNC(PyCodeObject *) +PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno); + +/* Return the line number associated with the specified bytecode index + in this code object. If you just need the line number of a frame, + use PyFrame_GetLineNumber() instead. */ +PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); + +/* for internal use only */ +typedef struct _addr_pair { + int ap_lower; + int ap_upper; +} PyAddrPair; + +#ifndef Py_LIMITED_API +/* Update *bounds to describe the first and one-past-the-last instructions in the + same line as lasti. Return the number of that line. +*/ +PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co, + int lasti, PyAddrPair *bounds); + +/* Create a comparable key used to compare constants taking in account the + * object type. It is used to make sure types are not coerced (e.g., float and + * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms + * + * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items) + * depending on the type and the value. The type is the first item to not + * compare bytes and str which can raise a BytesWarning exception. */ +PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj); +#endif + +PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, + PyObject *names, PyObject *lineno_obj); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CODE_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/codecs.h b/libs/nxpy/include/codecs.h index f8275a12..2bed53c3 100644 --- a/libs/nxpy/include/codecs.h +++ b/libs/nxpy/include/codecs.h @@ -1,236 +1,236 @@ -#ifndef Py_CODECREGISTRY_H -#define Py_CODECREGISTRY_H -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------------------------------------------------------------ - - Python Codec Registry and support functions - - -Written by Marc-Andre Lemburg (mal@lemburg.com). - -Copyright (c) Corporation for National Research Initiatives. - - ------------------------------------------------------------------------ */ - -/* Register a new codec search function. - - As side effect, this tries to load the encodings package, if not - yet done, to make sure that it is always first in the list of - search functions. - - The search_function's refcount is incremented by this function. */ - -PyAPI_FUNC(int) PyCodec_Register( - PyObject *search_function - ); - -/* Codec registry lookup API. - - Looks up the given encoding and returns a CodecInfo object with - function attributes which implement the different aspects of - processing the encoding. - - The encoding string is looked up converted to all lower-case - characters. This makes encodings looked up through this mechanism - effectively case-insensitive. - - If no codec is found, a KeyError is set and NULL returned. - - As side effect, this tries to load the encodings package, if not - yet done. This is part of the lazy load strategy for the encodings - package. - - */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyCodec_Lookup( - const char *encoding - ); - -PyAPI_FUNC(int) _PyCodec_Forget( - const char *encoding - ); -#endif - -/* Codec registry encoding check API. - - Returns 1/0 depending on whether there is a registered codec for - the given encoding. - -*/ - -PyAPI_FUNC(int) PyCodec_KnownEncoding( - const char *encoding - ); - -/* Generic codec based encoding API. - - object is passed through the encoder function found for the given - encoding using the error handling method defined by errors. errors - may be NULL to use the default method defined for the codec. - - Raises a LookupError in case no encoder can be found. - - */ - -PyAPI_FUNC(PyObject *) PyCodec_Encode( - PyObject *object, - const char *encoding, - const char *errors - ); - -/* Generic codec based decoding API. - - object is passed through the decoder function found for the given - encoding using the error handling method defined by errors. errors - may be NULL to use the default method defined for the codec. - - Raises a LookupError in case no encoder can be found. - - */ - -PyAPI_FUNC(PyObject *) PyCodec_Decode( - PyObject *object, - const char *encoding, - const char *errors - ); - -#ifndef Py_LIMITED_API -/* Text codec specific encoding and decoding API. - - Checks the encoding against a list of codecs which do not - implement a str<->bytes encoding before attempting the - operation. - - Please note that these APIs are internal and should not - be used in Python C extensions. - - XXX (ncoghlan): should we make these, or something like them, public - in Python 3.5+? - - */ -PyAPI_FUNC(PyObject *) _PyCodec_LookupTextEncoding( - const char *encoding, - const char *alternate_command - ); - -PyAPI_FUNC(PyObject *) _PyCodec_EncodeText( - PyObject *object, - const char *encoding, - const char *errors - ); - -PyAPI_FUNC(PyObject *) _PyCodec_DecodeText( - PyObject *object, - const char *encoding, - const char *errors - ); - -/* These two aren't actually text encoding specific, but _io.TextIOWrapper - * is the only current API consumer. - */ -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalDecoder( - PyObject *codec_info, - const char *errors - ); - -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalEncoder( - PyObject *codec_info, - const char *errors - ); -#endif - - - -/* --- Codec Lookup APIs -------------------------------------------------- - - All APIs return a codec object with incremented refcount and are - based on _PyCodec_Lookup(). The same comments w/r to the encoding - name also apply to these APIs. - -*/ - -/* Get an encoder function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_Encoder( - const char *encoding - ); - -/* Get a decoder function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_Decoder( - const char *encoding - ); - -/* Get an IncrementalEncoder object for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_IncrementalEncoder( - const char *encoding, - const char *errors - ); - -/* Get an IncrementalDecoder object function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_IncrementalDecoder( - const char *encoding, - const char *errors - ); - -/* Get a StreamReader factory function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_StreamReader( - const char *encoding, - PyObject *stream, - const char *errors - ); - -/* Get a StreamWriter factory function for the given encoding. */ - -PyAPI_FUNC(PyObject *) PyCodec_StreamWriter( - const char *encoding, - PyObject *stream, - const char *errors - ); - -/* Unicode encoding error handling callback registry API */ - -/* Register the error handling callback function error under the given - name. This function will be called by the codec when it encounters - unencodable characters/undecodable bytes and doesn't know the - callback name, when name is specified as the error parameter - in the call to the encode/decode function. - Return 0 on success, -1 on error */ -PyAPI_FUNC(int) PyCodec_RegisterError(const char *name, PyObject *error); - -/* Lookup the error handling callback function registered under the given - name. As a special case NULL can be passed, in which case - the error handling callback for "strict" will be returned. */ -PyAPI_FUNC(PyObject *) PyCodec_LookupError(const char *name); - -/* raise exc as an exception */ -PyAPI_FUNC(PyObject *) PyCodec_StrictErrors(PyObject *exc); - -/* ignore the unicode error, skipping the faulty input */ -PyAPI_FUNC(PyObject *) PyCodec_IgnoreErrors(PyObject *exc); - -/* replace the unicode encode error with ? or U+FFFD */ -PyAPI_FUNC(PyObject *) PyCodec_ReplaceErrors(PyObject *exc); - -/* replace the unicode encode error with XML character references */ -PyAPI_FUNC(PyObject *) PyCodec_XMLCharRefReplaceErrors(PyObject *exc); - -/* replace the unicode encode error with backslash escapes (\x, \u and \U) */ -PyAPI_FUNC(PyObject *) PyCodec_BackslashReplaceErrors(PyObject *exc); - -/* replace the unicode encode error with backslash escapes (\N, \x, \u and \U) */ -PyAPI_FUNC(PyObject *) PyCodec_NameReplaceErrors(PyObject *exc); - -PyAPI_DATA(const char *) Py_hexdigits; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CODECREGISTRY_H */ +#ifndef Py_CODECREGISTRY_H +#define Py_CODECREGISTRY_H +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------------ + + Python Codec Registry and support functions + + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +Copyright (c) Corporation for National Research Initiatives. + + ------------------------------------------------------------------------ */ + +/* Register a new codec search function. + + As side effect, this tries to load the encodings package, if not + yet done, to make sure that it is always first in the list of + search functions. + + The search_function's refcount is incremented by this function. */ + +PyAPI_FUNC(int) PyCodec_Register( + PyObject *search_function + ); + +/* Codec registry lookup API. + + Looks up the given encoding and returns a CodecInfo object with + function attributes which implement the different aspects of + processing the encoding. + + The encoding string is looked up converted to all lower-case + characters. This makes encodings looked up through this mechanism + effectively case-insensitive. + + If no codec is found, a KeyError is set and NULL returned. + + As side effect, this tries to load the encodings package, if not + yet done. This is part of the lazy load strategy for the encodings + package. + + */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyCodec_Lookup( + const char *encoding + ); + +PyAPI_FUNC(int) _PyCodec_Forget( + const char *encoding + ); +#endif + +/* Codec registry encoding check API. + + Returns 1/0 depending on whether there is a registered codec for + the given encoding. + +*/ + +PyAPI_FUNC(int) PyCodec_KnownEncoding( + const char *encoding + ); + +/* Generic codec based encoding API. + + object is passed through the encoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +PyAPI_FUNC(PyObject *) PyCodec_Encode( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* Generic codec based decoding API. + + object is passed through the decoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +PyAPI_FUNC(PyObject *) PyCodec_Decode( + PyObject *object, + const char *encoding, + const char *errors + ); + +#ifndef Py_LIMITED_API +/* Text codec specific encoding and decoding API. + + Checks the encoding against a list of codecs which do not + implement a str<->bytes encoding before attempting the + operation. + + Please note that these APIs are internal and should not + be used in Python C extensions. + + XXX (ncoghlan): should we make these, or something like them, public + in Python 3.5+? + + */ +PyAPI_FUNC(PyObject *) _PyCodec_LookupTextEncoding( + const char *encoding, + const char *alternate_command + ); + +PyAPI_FUNC(PyObject *) _PyCodec_EncodeText( + PyObject *object, + const char *encoding, + const char *errors + ); + +PyAPI_FUNC(PyObject *) _PyCodec_DecodeText( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* These two aren't actually text encoding specific, but _io.TextIOWrapper + * is the only current API consumer. + */ +PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalDecoder( + PyObject *codec_info, + const char *errors + ); + +PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalEncoder( + PyObject *codec_info, + const char *errors + ); +#endif + + + +/* --- Codec Lookup APIs -------------------------------------------------- + + All APIs return a codec object with incremented refcount and are + based on _PyCodec_Lookup(). The same comments w/r to the encoding + name also apply to these APIs. + +*/ + +/* Get an encoder function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_Encoder( + const char *encoding + ); + +/* Get a decoder function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_Decoder( + const char *encoding + ); + +/* Get an IncrementalEncoder object for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_IncrementalEncoder( + const char *encoding, + const char *errors + ); + +/* Get an IncrementalDecoder object function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_IncrementalDecoder( + const char *encoding, + const char *errors + ); + +/* Get a StreamReader factory function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_StreamReader( + const char *encoding, + PyObject *stream, + const char *errors + ); + +/* Get a StreamWriter factory function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_StreamWriter( + const char *encoding, + PyObject *stream, + const char *errors + ); + +/* Unicode encoding error handling callback registry API */ + +/* Register the error handling callback function error under the given + name. This function will be called by the codec when it encounters + unencodable characters/undecodable bytes and doesn't know the + callback name, when name is specified as the error parameter + in the call to the encode/decode function. + Return 0 on success, -1 on error */ +PyAPI_FUNC(int) PyCodec_RegisterError(const char *name, PyObject *error); + +/* Lookup the error handling callback function registered under the given + name. As a special case NULL can be passed, in which case + the error handling callback for "strict" will be returned. */ +PyAPI_FUNC(PyObject *) PyCodec_LookupError(const char *name); + +/* raise exc as an exception */ +PyAPI_FUNC(PyObject *) PyCodec_StrictErrors(PyObject *exc); + +/* ignore the unicode error, skipping the faulty input */ +PyAPI_FUNC(PyObject *) PyCodec_IgnoreErrors(PyObject *exc); + +/* replace the unicode encode error with ? or U+FFFD */ +PyAPI_FUNC(PyObject *) PyCodec_ReplaceErrors(PyObject *exc); + +/* replace the unicode encode error with XML character references */ +PyAPI_FUNC(PyObject *) PyCodec_XMLCharRefReplaceErrors(PyObject *exc); + +/* replace the unicode encode error with backslash escapes (\x, \u and \U) */ +PyAPI_FUNC(PyObject *) PyCodec_BackslashReplaceErrors(PyObject *exc); + +/* replace the unicode encode error with backslash escapes (\N, \x, \u and \U) */ +PyAPI_FUNC(PyObject *) PyCodec_NameReplaceErrors(PyObject *exc); + +PyAPI_DATA(const char *) Py_hexdigits; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CODECREGISTRY_H */ diff --git a/libs/nxpy/include/compile.h b/libs/nxpy/include/compile.h index ecd8dc1d..5ddf4a61 100644 --- a/libs/nxpy/include/compile.h +++ b/libs/nxpy/include/compile.h @@ -1,73 +1,73 @@ -#ifndef Py_COMPILE_H -#define Py_COMPILE_H - -#ifndef Py_LIMITED_API -#include "code.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Public interface */ -struct _node; /* Declare the existence of this type */ -PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *); - -/* Future feature support */ - -typedef struct { - int ff_features; /* flags set by future statements */ - int ff_lineno; /* line number of last future statement */ -} PyFutureFeatures; - -#define FUTURE_NESTED_SCOPES "nested_scopes" -#define FUTURE_GENERATORS "generators" -#define FUTURE_DIVISION "division" -#define FUTURE_ABSOLUTE_IMPORT "absolute_import" -#define FUTURE_WITH_STATEMENT "with_statement" -#define FUTURE_PRINT_FUNCTION "print_function" -#define FUTURE_UNICODE_LITERALS "unicode_literals" -#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL" -#define FUTURE_GENERATOR_STOP "generator_stop" - -struct _mod; /* Declare the existence of this type */ -#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar) -PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx( - struct _mod *mod, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags, - int optimize, - PyArena *arena); -PyAPI_FUNC(PyCodeObject *) PyAST_CompileObject( - struct _mod *mod, - PyObject *filename, - PyCompilerFlags *flags, - int optimize, - PyArena *arena); -PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST( - struct _mod * mod, - const char *filename /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromASTObject( - struct _mod * mod, - PyObject *filename - ); - -/* _Py_Mangle is defined in compile.c */ -PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); - -#define PY_INVALID_STACK_EFFECT INT_MAX -PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_LIMITED_API */ - -/* These definitions must match corresponding definitions in graminit.h. - There's code in compile.c that checks that they are the same. */ -#define Py_single_input 256 -#define Py_file_input 257 -#define Py_eval_input 258 - -#endif /* !Py_COMPILE_H */ +#ifndef Py_COMPILE_H +#define Py_COMPILE_H + +#ifndef Py_LIMITED_API +#include "code.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Public interface */ +struct _node; /* Declare the existence of this type */ +PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *); + +/* Future feature support */ + +typedef struct { + int ff_features; /* flags set by future statements */ + int ff_lineno; /* line number of last future statement */ +} PyFutureFeatures; + +#define FUTURE_NESTED_SCOPES "nested_scopes" +#define FUTURE_GENERATORS "generators" +#define FUTURE_DIVISION "division" +#define FUTURE_ABSOLUTE_IMPORT "absolute_import" +#define FUTURE_WITH_STATEMENT "with_statement" +#define FUTURE_PRINT_FUNCTION "print_function" +#define FUTURE_UNICODE_LITERALS "unicode_literals" +#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL" +#define FUTURE_GENERATOR_STOP "generator_stop" + +struct _mod; /* Declare the existence of this type */ +#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar) +PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx( + struct _mod *mod, + const char *filename, /* decoded from the filesystem encoding */ + PyCompilerFlags *flags, + int optimize, + PyArena *arena); +PyAPI_FUNC(PyCodeObject *) PyAST_CompileObject( + struct _mod *mod, + PyObject *filename, + PyCompilerFlags *flags, + int optimize, + PyArena *arena); +PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST( + struct _mod * mod, + const char *filename /* decoded from the filesystem encoding */ + ); +PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromASTObject( + struct _mod * mod, + PyObject *filename + ); + +/* _Py_Mangle is defined in compile.c */ +PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); + +#define PY_INVALID_STACK_EFFECT INT_MAX +PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_LIMITED_API */ + +/* These definitions must match corresponding definitions in graminit.h. + There's code in compile.c that checks that they are the same. */ +#define Py_single_input 256 +#define Py_file_input 257 +#define Py_eval_input 258 + +#endif /* !Py_COMPILE_H */ diff --git a/libs/nxpy/include/complexobject.h b/libs/nxpy/include/complexobject.h index cb8c52c5..a189212d 100644 --- a/libs/nxpy/include/complexobject.h +++ b/libs/nxpy/include/complexobject.h @@ -1,69 +1,69 @@ -/* Complex number structure */ - -#ifndef Py_COMPLEXOBJECT_H -#define Py_COMPLEXOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -typedef struct { - double real; - double imag; -} Py_complex; - -/* Operations on complex numbers from complexmodule.c */ - -PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex); -PyAPI_FUNC(double) _Py_c_abs(Py_complex); -#endif - -/* Complex object interface */ - -/* -PyComplexObject represents a complex number with double-precision -real and imaginary parts. -*/ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - Py_complex cval; -} PyComplexObject; -#endif - -PyAPI_DATA(PyTypeObject) PyComplex_Type; - -#define PyComplex_Check(op) PyObject_TypeCheck(op, &PyComplex_Type) -#define PyComplex_CheckExact(op) (Py_TYPE(op) == &PyComplex_Type) - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex); -#endif -PyAPI_FUNC(PyObject *) PyComplex_FromDoubles(double real, double imag); - -PyAPI_FUNC(double) PyComplex_RealAsDouble(PyObject *op); -PyAPI_FUNC(double) PyComplex_ImagAsDouble(PyObject *op); -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op); -#endif - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyComplex_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_COMPLEXOBJECT_H */ +/* Complex number structure */ + +#ifndef Py_COMPLEXOBJECT_H +#define Py_COMPLEXOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +typedef struct { + double real; + double imag; +} Py_complex; + +/* Operations on complex numbers from complexmodule.c */ + +PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex); +PyAPI_FUNC(double) _Py_c_abs(Py_complex); +#endif + +/* Complex object interface */ + +/* +PyComplexObject represents a complex number with double-precision +real and imaginary parts. +*/ +#ifndef Py_LIMITED_API +typedef struct { + PyObject_HEAD + Py_complex cval; +} PyComplexObject; +#endif + +PyAPI_DATA(PyTypeObject) PyComplex_Type; + +#define PyComplex_Check(op) PyObject_TypeCheck(op, &PyComplex_Type) +#define PyComplex_CheckExact(op) (Py_TYPE(op) == &PyComplex_Type) + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex); +#endif +PyAPI_FUNC(PyObject *) PyComplex_FromDoubles(double real, double imag); + +PyAPI_FUNC(double) PyComplex_RealAsDouble(PyObject *op); +PyAPI_FUNC(double) PyComplex_ImagAsDouble(PyObject *op); +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op); +#endif + +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyComplex_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_COMPLEXOBJECT_H */ diff --git a/libs/nxpy/include/datetime.h b/libs/nxpy/include/datetime.h index 06cbc4ab..018ec80d 100644 --- a/libs/nxpy/include/datetime.h +++ b/libs/nxpy/include/datetime.h @@ -1,243 +1,243 @@ -/* datetime.h - */ -#ifndef Py_LIMITED_API -#ifndef DATETIME_H -#define DATETIME_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Fields are packed into successive bytes, each viewed as unsigned and - * big-endian, unless otherwise noted: - * - * byte offset - * 0 year 2 bytes, 1-9999 - * 2 month 1 byte, 1-12 - * 3 day 1 byte, 1-31 - * 4 hour 1 byte, 0-23 - * 5 minute 1 byte, 0-59 - * 6 second 1 byte, 0-59 - * 7 usecond 3 bytes, 0-999999 - * 10 - */ - -/* # of bytes for year, month, and day. */ -#define _PyDateTime_DATE_DATASIZE 4 - -/* # of bytes for hour, minute, second, and usecond. */ -#define _PyDateTime_TIME_DATASIZE 6 - -/* # of bytes for year, month, day, hour, minute, second, and usecond. */ -#define _PyDateTime_DATETIME_DATASIZE 10 - - -typedef struct -{ - PyObject_HEAD - Py_hash_t hashcode; /* -1 when unknown */ - int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */ - int seconds; /* 0 <= seconds < 24*3600 is invariant */ - int microseconds; /* 0 <= microseconds < 1000000 is invariant */ -} PyDateTime_Delta; - -typedef struct -{ - PyObject_HEAD /* a pure abstract base class */ -} PyDateTime_TZInfo; - - -/* The datetime and time types have hashcodes, and an optional tzinfo member, - * present if and only if hastzinfo is true. - */ -#define _PyTZINFO_HEAD \ - PyObject_HEAD \ - Py_hash_t hashcode; \ - char hastzinfo; /* boolean flag */ - -/* No _PyDateTime_BaseTZInfo is allocated; it's just to have something - * convenient to cast to, when getting at the hastzinfo member of objects - * starting with _PyTZINFO_HEAD. - */ -typedef struct -{ - _PyTZINFO_HEAD -} _PyDateTime_BaseTZInfo; - -/* All time objects are of PyDateTime_TimeType, but that can be allocated - * in two ways, with or without a tzinfo member. Without is the same as - * tzinfo == None, but consumes less memory. _PyDateTime_BaseTime is an - * internal struct used to allocate the right amount of space for the - * "without" case. - */ -#define _PyDateTime_TIMEHEAD \ - _PyTZINFO_HEAD \ - unsigned char data[_PyDateTime_TIME_DATASIZE]; - -typedef struct -{ - _PyDateTime_TIMEHEAD -} _PyDateTime_BaseTime; /* hastzinfo false */ - -typedef struct -{ - _PyDateTime_TIMEHEAD - PyObject *tzinfo; -} PyDateTime_Time; /* hastzinfo true */ - - -/* All datetime objects are of PyDateTime_DateTimeType, but that can be - * allocated in two ways too, just like for time objects above. In addition, - * the plain date type is a base class for datetime, so it must also have - * a hastzinfo member (although it's unused there). - */ -typedef struct -{ - _PyTZINFO_HEAD - unsigned char data[_PyDateTime_DATE_DATASIZE]; -} PyDateTime_Date; - -#define _PyDateTime_DATETIMEHEAD \ - _PyTZINFO_HEAD \ - unsigned char data[_PyDateTime_DATETIME_DATASIZE]; - -typedef struct -{ - _PyDateTime_DATETIMEHEAD -} _PyDateTime_BaseDateTime; /* hastzinfo false */ - -typedef struct -{ - _PyDateTime_DATETIMEHEAD - PyObject *tzinfo; -} PyDateTime_DateTime; /* hastzinfo true */ - - -/* Apply for date and datetime instances. */ -#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \ - ((PyDateTime_Date*)o)->data[1]) -#define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2]) -#define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3]) - -#define PyDateTime_DATE_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4]) -#define PyDateTime_DATE_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5]) -#define PyDateTime_DATE_GET_SECOND(o) (((PyDateTime_DateTime*)o)->data[6]) -#define PyDateTime_DATE_GET_MICROSECOND(o) \ - ((((PyDateTime_DateTime*)o)->data[7] << 16) | \ - (((PyDateTime_DateTime*)o)->data[8] << 8) | \ - ((PyDateTime_DateTime*)o)->data[9]) - -/* Apply for time instances. */ -#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0]) -#define PyDateTime_TIME_GET_MINUTE(o) (((PyDateTime_Time*)o)->data[1]) -#define PyDateTime_TIME_GET_SECOND(o) (((PyDateTime_Time*)o)->data[2]) -#define PyDateTime_TIME_GET_MICROSECOND(o) \ - ((((PyDateTime_Time*)o)->data[3] << 16) | \ - (((PyDateTime_Time*)o)->data[4] << 8) | \ - ((PyDateTime_Time*)o)->data[5]) - -/* Apply for time delta instances */ -#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) -#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) -#define PyDateTime_DELTA_GET_MICROSECONDS(o) \ - (((PyDateTime_Delta*)o)->microseconds) - - -/* Define structure for C API. */ -typedef struct { - /* type objects */ - PyTypeObject *DateType; - PyTypeObject *DateTimeType; - PyTypeObject *TimeType; - PyTypeObject *DeltaType; - PyTypeObject *TZInfoType; - - /* constructors */ - PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*); - PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, - PyObject*, PyTypeObject*); - PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*); - PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*); - - /* constructors for the DB API */ - PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*); - PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*); - -} PyDateTime_CAPI; - -#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" - - -#ifdef Py_BUILD_CORE - -/* Macros for type checking when building the Python core. */ -#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) -#define PyDate_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DateType) - -#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType) -#define PyDateTime_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DateTimeType) - -#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) -#define PyTime_CheckExact(op) (Py_TYPE(op) == &PyDateTime_TimeType) - -#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType) -#define PyDelta_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DeltaType) - -#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) -#define PyTZInfo_CheckExact(op) (Py_TYPE(op) == &PyDateTime_TZInfoType) - -#else - -/* Define global variable for the C API and a macro for setting it. */ -static PyDateTime_CAPI *PyDateTimeAPI = NULL; - -#define PyDateTime_IMPORT \ - PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0) - -/* Macros for type checking when not building the Python core. */ -#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) -#define PyDate_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DateType) - -#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) -#define PyDateTime_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DateTimeType) - -#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) -#define PyTime_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->TimeType) - -#define PyDelta_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DeltaType) -#define PyDelta_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DeltaType) - -#define PyTZInfo_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TZInfoType) -#define PyTZInfo_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->TZInfoType) - -/* Macros for accessing constructors in a simplified fashion. */ -#define PyDate_FromDate(year, month, day) \ - PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType) - -#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \ - PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \ - min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType) - -#define PyTime_FromTime(hour, minute, second, usecond) \ - PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \ - Py_None, PyDateTimeAPI->TimeType) - -#define PyDelta_FromDSU(days, seconds, useconds) \ - PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \ - PyDateTimeAPI->DeltaType) - -/* Macros supporting the DB API. */ -#define PyDateTime_FromTimestamp(args) \ - PyDateTimeAPI->DateTime_FromTimestamp( \ - (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL) - -#define PyDate_FromTimestamp(args) \ - PyDateTimeAPI->Date_FromTimestamp( \ - (PyObject*) (PyDateTimeAPI->DateType), args) - -#endif /* Py_BUILD_CORE */ - -#ifdef __cplusplus -} -#endif -#endif -#endif /* !Py_LIMITED_API */ +/* datetime.h + */ +#ifndef Py_LIMITED_API +#ifndef DATETIME_H +#define DATETIME_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Fields are packed into successive bytes, each viewed as unsigned and + * big-endian, unless otherwise noted: + * + * byte offset + * 0 year 2 bytes, 1-9999 + * 2 month 1 byte, 1-12 + * 3 day 1 byte, 1-31 + * 4 hour 1 byte, 0-23 + * 5 minute 1 byte, 0-59 + * 6 second 1 byte, 0-59 + * 7 usecond 3 bytes, 0-999999 + * 10 + */ + +/* # of bytes for year, month, and day. */ +#define _PyDateTime_DATE_DATASIZE 4 + +/* # of bytes for hour, minute, second, and usecond. */ +#define _PyDateTime_TIME_DATASIZE 6 + +/* # of bytes for year, month, day, hour, minute, second, and usecond. */ +#define _PyDateTime_DATETIME_DATASIZE 10 + + +typedef struct +{ + PyObject_HEAD + Py_hash_t hashcode; /* -1 when unknown */ + int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */ + int seconds; /* 0 <= seconds < 24*3600 is invariant */ + int microseconds; /* 0 <= microseconds < 1000000 is invariant */ +} PyDateTime_Delta; + +typedef struct +{ + PyObject_HEAD /* a pure abstract base class */ +} PyDateTime_TZInfo; + + +/* The datetime and time types have hashcodes, and an optional tzinfo member, + * present if and only if hastzinfo is true. + */ +#define _PyTZINFO_HEAD \ + PyObject_HEAD \ + Py_hash_t hashcode; \ + char hastzinfo; /* boolean flag */ + +/* No _PyDateTime_BaseTZInfo is allocated; it's just to have something + * convenient to cast to, when getting at the hastzinfo member of objects + * starting with _PyTZINFO_HEAD. + */ +typedef struct +{ + _PyTZINFO_HEAD +} _PyDateTime_BaseTZInfo; + +/* All time objects are of PyDateTime_TimeType, but that can be allocated + * in two ways, with or without a tzinfo member. Without is the same as + * tzinfo == None, but consumes less memory. _PyDateTime_BaseTime is an + * internal struct used to allocate the right amount of space for the + * "without" case. + */ +#define _PyDateTime_TIMEHEAD \ + _PyTZINFO_HEAD \ + unsigned char data[_PyDateTime_TIME_DATASIZE]; + +typedef struct +{ + _PyDateTime_TIMEHEAD +} _PyDateTime_BaseTime; /* hastzinfo false */ + +typedef struct +{ + _PyDateTime_TIMEHEAD + PyObject *tzinfo; +} PyDateTime_Time; /* hastzinfo true */ + + +/* All datetime objects are of PyDateTime_DateTimeType, but that can be + * allocated in two ways too, just like for time objects above. In addition, + * the plain date type is a base class for datetime, so it must also have + * a hastzinfo member (although it's unused there). + */ +typedef struct +{ + _PyTZINFO_HEAD + unsigned char data[_PyDateTime_DATE_DATASIZE]; +} PyDateTime_Date; + +#define _PyDateTime_DATETIMEHEAD \ + _PyTZINFO_HEAD \ + unsigned char data[_PyDateTime_DATETIME_DATASIZE]; + +typedef struct +{ + _PyDateTime_DATETIMEHEAD +} _PyDateTime_BaseDateTime; /* hastzinfo false */ + +typedef struct +{ + _PyDateTime_DATETIMEHEAD + PyObject *tzinfo; +} PyDateTime_DateTime; /* hastzinfo true */ + + +/* Apply for date and datetime instances. */ +#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \ + ((PyDateTime_Date*)o)->data[1]) +#define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2]) +#define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3]) + +#define PyDateTime_DATE_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4]) +#define PyDateTime_DATE_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5]) +#define PyDateTime_DATE_GET_SECOND(o) (((PyDateTime_DateTime*)o)->data[6]) +#define PyDateTime_DATE_GET_MICROSECOND(o) \ + ((((PyDateTime_DateTime*)o)->data[7] << 16) | \ + (((PyDateTime_DateTime*)o)->data[8] << 8) | \ + ((PyDateTime_DateTime*)o)->data[9]) + +/* Apply for time instances. */ +#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0]) +#define PyDateTime_TIME_GET_MINUTE(o) (((PyDateTime_Time*)o)->data[1]) +#define PyDateTime_TIME_GET_SECOND(o) (((PyDateTime_Time*)o)->data[2]) +#define PyDateTime_TIME_GET_MICROSECOND(o) \ + ((((PyDateTime_Time*)o)->data[3] << 16) | \ + (((PyDateTime_Time*)o)->data[4] << 8) | \ + ((PyDateTime_Time*)o)->data[5]) + +/* Apply for time delta instances */ +#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) +#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) +#define PyDateTime_DELTA_GET_MICROSECONDS(o) \ + (((PyDateTime_Delta*)o)->microseconds) + + +/* Define structure for C API. */ +typedef struct { + /* type objects */ + PyTypeObject *DateType; + PyTypeObject *DateTimeType; + PyTypeObject *TimeType; + PyTypeObject *DeltaType; + PyTypeObject *TZInfoType; + + /* constructors */ + PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*); + PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, + PyObject*, PyTypeObject*); + PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*); + PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*); + + /* constructors for the DB API */ + PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*); + PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*); + +} PyDateTime_CAPI; + +#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" + + +#ifdef Py_BUILD_CORE + +/* Macros for type checking when building the Python core. */ +#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) +#define PyDate_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DateType) + +#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType) +#define PyDateTime_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DateTimeType) + +#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) +#define PyTime_CheckExact(op) (Py_TYPE(op) == &PyDateTime_TimeType) + +#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType) +#define PyDelta_CheckExact(op) (Py_TYPE(op) == &PyDateTime_DeltaType) + +#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) +#define PyTZInfo_CheckExact(op) (Py_TYPE(op) == &PyDateTime_TZInfoType) + +#else + +/* Define global variable for the C API and a macro for setting it. */ +static PyDateTime_CAPI *PyDateTimeAPI = NULL; + +#define PyDateTime_IMPORT \ + PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0) + +/* Macros for type checking when not building the Python core. */ +#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) +#define PyDate_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DateType) + +#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) +#define PyDateTime_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DateTimeType) + +#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) +#define PyTime_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->TimeType) + +#define PyDelta_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DeltaType) +#define PyDelta_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->DeltaType) + +#define PyTZInfo_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TZInfoType) +#define PyTZInfo_CheckExact(op) (Py_TYPE(op) == PyDateTimeAPI->TZInfoType) + +/* Macros for accessing constructors in a simplified fashion. */ +#define PyDate_FromDate(year, month, day) \ + PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType) + +#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \ + PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \ + min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType) + +#define PyTime_FromTime(hour, minute, second, usecond) \ + PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \ + Py_None, PyDateTimeAPI->TimeType) + +#define PyDelta_FromDSU(days, seconds, useconds) \ + PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \ + PyDateTimeAPI->DeltaType) + +/* Macros supporting the DB API. */ +#define PyDateTime_FromTimestamp(args) \ + PyDateTimeAPI->DateTime_FromTimestamp( \ + (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL) + +#define PyDate_FromTimestamp(args) \ + PyDateTimeAPI->Date_FromTimestamp( \ + (PyObject*) (PyDateTimeAPI->DateType), args) + +#endif /* Py_BUILD_CORE */ + +#ifdef __cplusplus +} +#endif +#endif +#endif /* !Py_LIMITED_API */ diff --git a/libs/nxpy/include/descrobject.h b/libs/nxpy/include/descrobject.h index e2ba97fc..1a62e9a0 100644 --- a/libs/nxpy/include/descrobject.h +++ b/libs/nxpy/include/descrobject.h @@ -1,105 +1,105 @@ -/* Descriptors */ -#ifndef Py_DESCROBJECT_H -#define Py_DESCROBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef PyObject *(*getter)(PyObject *, void *); -typedef int (*setter)(PyObject *, PyObject *, void *); - -typedef struct PyGetSetDef { - char *name; - getter get; - setter set; - char *doc; - void *closure; -} PyGetSetDef; - -#ifndef Py_LIMITED_API -typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, - void *wrapped); - -typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, - void *wrapped, PyObject *kwds); - -struct wrapperbase { - char *name; - int offset; - void *function; - wrapperfunc wrapper; - char *doc; - int flags; - PyObject *name_strobj; -}; - -/* Flags for above struct */ -#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */ - -/* Various kinds of descriptor objects */ - -typedef struct { - PyObject_HEAD - PyTypeObject *d_type; - PyObject *d_name; - PyObject *d_qualname; -} PyDescrObject; - -#define PyDescr_COMMON PyDescrObject d_common - -#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) -#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) - -typedef struct { - PyDescr_COMMON; - PyMethodDef *d_method; -} PyMethodDescrObject; - -typedef struct { - PyDescr_COMMON; - struct PyMemberDef *d_member; -} PyMemberDescrObject; - -typedef struct { - PyDescr_COMMON; - PyGetSetDef *d_getset; -} PyGetSetDescrObject; - -typedef struct { - PyDescr_COMMON; - struct wrapperbase *d_base; - void *d_wrapped; /* This can be any function pointer */ -} PyWrapperDescrObject; -#endif /* Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type; -PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type; -PyAPI_DATA(PyTypeObject) PyMemberDescr_Type; -PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; -PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; -PyAPI_DATA(PyTypeObject) PyDictProxy_Type; -PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type; - -PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *); -PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *); -struct PyMemberDef; /* forward declaration for following prototype */ -PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *, - struct PyMemberDef *); -PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, - struct PyGetSetDef *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *, - struct wrapperbase *, void *); -#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL) -#endif - -PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); -PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); - - -PyAPI_DATA(PyTypeObject) PyProperty_Type; -#ifdef __cplusplus -} -#endif -#endif /* !Py_DESCROBJECT_H */ - +/* Descriptors */ +#ifndef Py_DESCROBJECT_H +#define Py_DESCROBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef PyObject *(*getter)(PyObject *, void *); +typedef int (*setter)(PyObject *, PyObject *, void *); + +typedef struct PyGetSetDef { + char *name; + getter get; + setter set; + char *doc; + void *closure; +} PyGetSetDef; + +#ifndef Py_LIMITED_API +typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, + void *wrapped); + +typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, + void *wrapped, PyObject *kwds); + +struct wrapperbase { + char *name; + int offset; + void *function; + wrapperfunc wrapper; + char *doc; + int flags; + PyObject *name_strobj; +}; + +/* Flags for above struct */ +#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */ + +/* Various kinds of descriptor objects */ + +typedef struct { + PyObject_HEAD + PyTypeObject *d_type; + PyObject *d_name; + PyObject *d_qualname; +} PyDescrObject; + +#define PyDescr_COMMON PyDescrObject d_common + +#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) +#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) + +typedef struct { + PyDescr_COMMON; + PyMethodDef *d_method; +} PyMethodDescrObject; + +typedef struct { + PyDescr_COMMON; + struct PyMemberDef *d_member; +} PyMemberDescrObject; + +typedef struct { + PyDescr_COMMON; + PyGetSetDef *d_getset; +} PyGetSetDescrObject; + +typedef struct { + PyDescr_COMMON; + struct wrapperbase *d_base; + void *d_wrapped; /* This can be any function pointer */ +} PyWrapperDescrObject; +#endif /* Py_LIMITED_API */ + +PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type; +PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type; +PyAPI_DATA(PyTypeObject) PyMemberDescr_Type; +PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; +PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; +PyAPI_DATA(PyTypeObject) PyDictProxy_Type; +PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type; + +PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *); +struct PyMemberDef; /* forward declaration for following prototype */ +PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *, + struct PyMemberDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, + struct PyGetSetDef *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *, + struct wrapperbase *, void *); +#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL) +#endif + +PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); +PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); + + +PyAPI_DATA(PyTypeObject) PyProperty_Type; +#ifdef __cplusplus +} +#endif +#endif /* !Py_DESCROBJECT_H */ + diff --git a/libs/nxpy/include/dictobject.h b/libs/nxpy/include/dictobject.h index e0e1c26a..16bded7b 100644 --- a/libs/nxpy/include/dictobject.h +++ b/libs/nxpy/include/dictobject.h @@ -1,153 +1,153 @@ -#ifndef Py_DICTOBJECT_H -#define Py_DICTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Dictionary object type -- mapping from hashable object to object */ - -/* The distribution includes a separate file, Objects/dictnotes.txt, - describing explorations into dictionary design and optimization. - It covers typical dictionary use patterns, the parameters for - tuning dictionaries, and several ideas for possible optimizations. -*/ - -#ifndef Py_LIMITED_API - -typedef struct _dictkeysobject PyDictKeysObject; - -/* The ma_values pointer is NULL for a combined table - * or points to an array of PyObject* for a split table - */ -typedef struct { - PyObject_HEAD - Py_ssize_t ma_used; - PyDictKeysObject *ma_keys; - PyObject **ma_values; -} PyDictObject; - -typedef struct { - PyObject_HEAD - PyDictObject *dv_dict; -} _PyDictViewObject; - -#endif /* Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PyDict_Type; -PyAPI_DATA(PyTypeObject) PyDictIterKey_Type; -PyAPI_DATA(PyTypeObject) PyDictIterValue_Type; -PyAPI_DATA(PyTypeObject) PyDictIterItem_Type; -PyAPI_DATA(PyTypeObject) PyDictKeys_Type; -PyAPI_DATA(PyTypeObject) PyDictItems_Type; -PyAPI_DATA(PyTypeObject) PyDictValues_Type; - -#define PyDict_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS) -#define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) -#define PyDictKeys_Check(op) PyObject_TypeCheck(op, &PyDictKeys_Type) -#define PyDictItems_Check(op) PyObject_TypeCheck(op, &PyDictItems_Type) -#define PyDictValues_Check(op) PyObject_TypeCheck(op, &PyDictValues_Type) -/* This excludes Values, since they are not sets. */ -# define PyDictViewSet_Check(op) \ - (PyDictKeys_Check(op) || PyDictItems_Check(op)) - - -PyAPI_FUNC(PyObject *) PyDict_New(void); -PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key, - Py_hash_t hash); -#endif -PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key); -PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp, - struct _Py_Identifier *key); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyDict_SetDefault( - PyObject *mp, PyObject *key, PyObject *defaultobj); -#endif -PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, - PyObject *item, Py_hash_t hash); -#endif -PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key, - Py_hash_t hash); -PyAPI_FUNC(int) _PyDict_DelItemIf(PyObject *mp, PyObject *key, - int (*predicate)(PyObject *value)); -#endif -PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); -PyAPI_FUNC(int) PyDict_Next( - PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value); -#ifndef Py_LIMITED_API -PyDictKeysObject *_PyDict_NewKeysForClass(void); -PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *); -PyAPI_FUNC(int) _PyDict_Next( - PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash); -PyObject *_PyDictView_New(PyObject *, PyTypeObject *); -#endif -PyAPI_FUNC(PyObject *) PyDict_Keys(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp); -PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp); -PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp); -PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, Py_hash_t hash); -PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused); -PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); -PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); -Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); -Py_ssize_t _PyDict_SizeOf(PyDictObject *); -PyObject *_PyDict_Pop(PyDictObject *, PyObject *, PyObject *); -PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); -#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) - -PyAPI_FUNC(int) PyDict_ClearFreeList(void); -#endif - -/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */ -PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other); - -/* PyDict_Merge updates/merges from a mapping object (an object that - supports PyMapping_Keys() and PyObject_GetItem()). If override is true, - the last occurrence of a key wins, else the first. The Python - dict.update(other) is equivalent to PyDict_Merge(dict, other, 1). -*/ -PyAPI_FUNC(int) PyDict_Merge(PyObject *mp, - PyObject *other, - int override); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); -#endif - -/* PyDict_MergeFromSeq2 updates/merges from an iterable object producing - iterable objects of length 2. If override is true, the last occurrence - of a key wins, else the first. The Python dict constructor dict(seq2) - is equivalent to dict={}; PyDict_MergeFromSeq(dict, seq2, 1). -*/ -PyAPI_FUNC(int) PyDict_MergeFromSeq2(PyObject *d, - PyObject *seq2, - int override); - -PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key); -PyAPI_FUNC(PyObject *) _PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key); -PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); -PyAPI_FUNC(int) _PyDict_SetItemId(PyObject *dp, struct _Py_Identifier *key, PyObject *item); -PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyDict_DelItemId(PyObject *mp, struct _Py_Identifier *key); -PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out); - -int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value); -PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_DICTOBJECT_H */ +#ifndef Py_DICTOBJECT_H +#define Py_DICTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Dictionary object type -- mapping from hashable object to object */ + +/* The distribution includes a separate file, Objects/dictnotes.txt, + describing explorations into dictionary design and optimization. + It covers typical dictionary use patterns, the parameters for + tuning dictionaries, and several ideas for possible optimizations. +*/ + +#ifndef Py_LIMITED_API + +typedef struct _dictkeysobject PyDictKeysObject; + +/* The ma_values pointer is NULL for a combined table + * or points to an array of PyObject* for a split table + */ +typedef struct { + PyObject_HEAD + Py_ssize_t ma_used; + PyDictKeysObject *ma_keys; + PyObject **ma_values; +} PyDictObject; + +typedef struct { + PyObject_HEAD + PyDictObject *dv_dict; +} _PyDictViewObject; + +#endif /* Py_LIMITED_API */ + +PyAPI_DATA(PyTypeObject) PyDict_Type; +PyAPI_DATA(PyTypeObject) PyDictIterKey_Type; +PyAPI_DATA(PyTypeObject) PyDictIterValue_Type; +PyAPI_DATA(PyTypeObject) PyDictIterItem_Type; +PyAPI_DATA(PyTypeObject) PyDictKeys_Type; +PyAPI_DATA(PyTypeObject) PyDictItems_Type; +PyAPI_DATA(PyTypeObject) PyDictValues_Type; + +#define PyDict_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS) +#define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) +#define PyDictKeys_Check(op) PyObject_TypeCheck(op, &PyDictKeys_Type) +#define PyDictItems_Check(op) PyObject_TypeCheck(op, &PyDictItems_Type) +#define PyDictValues_Check(op) PyObject_TypeCheck(op, &PyDictValues_Type) +/* This excludes Values, since they are not sets. */ +# define PyDictViewSet_Check(op) \ + (PyDictKeys_Check(op) || PyDictItems_Check(op)) + + +PyAPI_FUNC(PyObject *) PyDict_New(void); +PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key, + Py_hash_t hash); +#endif +PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key); +PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp, + struct _Py_Identifier *key); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyDict_SetDefault( + PyObject *mp, PyObject *key, PyObject *defaultobj); +#endif +PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, + PyObject *item, Py_hash_t hash); +#endif +PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key, + Py_hash_t hash); +PyAPI_FUNC(int) _PyDict_DelItemIf(PyObject *mp, PyObject *key, + int (*predicate)(PyObject *value)); +#endif +PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); +PyAPI_FUNC(int) PyDict_Next( + PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value); +#ifndef Py_LIMITED_API +PyDictKeysObject *_PyDict_NewKeysForClass(void); +PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *); +PyAPI_FUNC(int) _PyDict_Next( + PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash); +PyObject *_PyDictView_New(PyObject *, PyTypeObject *); +#endif +PyAPI_FUNC(PyObject *) PyDict_Keys(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp); +PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp); +PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, Py_hash_t hash); +PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused); +PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); +PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); +Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); +Py_ssize_t _PyDict_SizeOf(PyDictObject *); +PyObject *_PyDict_Pop(PyDictObject *, PyObject *, PyObject *); +PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); +#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) + +PyAPI_FUNC(int) PyDict_ClearFreeList(void); +#endif + +/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */ +PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other); + +/* PyDict_Merge updates/merges from a mapping object (an object that + supports PyMapping_Keys() and PyObject_GetItem()). If override is true, + the last occurrence of a key wins, else the first. The Python + dict.update(other) is equivalent to PyDict_Merge(dict, other, 1). +*/ +PyAPI_FUNC(int) PyDict_Merge(PyObject *mp, + PyObject *other, + int override); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); +#endif + +/* PyDict_MergeFromSeq2 updates/merges from an iterable object producing + iterable objects of length 2. If override is true, the last occurrence + of a key wins, else the first. The Python dict constructor dict(seq2) + is equivalent to dict={}; PyDict_MergeFromSeq(dict, seq2, 1). +*/ +PyAPI_FUNC(int) PyDict_MergeFromSeq2(PyObject *d, + PyObject *seq2, + int override); + +PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key); +PyAPI_FUNC(PyObject *) _PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key); +PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); +PyAPI_FUNC(int) _PyDict_SetItemId(PyObject *dp, struct _Py_Identifier *key, PyObject *item); +PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyDict_DelItemId(PyObject *mp, struct _Py_Identifier *key); +PyAPI_FUNC(void) _PyDict_DebugMallocStats(FILE *out); + +int _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *name, PyObject *value); +PyObject *_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_DICTOBJECT_H */ diff --git a/libs/nxpy/include/dtoa.h b/libs/nxpy/include/dtoa.h index 9bfb6251..0901d8fb 100644 --- a/libs/nxpy/include/dtoa.h +++ b/libs/nxpy/include/dtoa.h @@ -1,19 +1,19 @@ -#ifndef Py_LIMITED_API -#ifndef PY_NO_SHORT_FLOAT_REPR -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr); -PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits, - int *decpt, int *sign, char **rve); -PyAPI_FUNC(void) _Py_dg_freedtoa(char *s); -PyAPI_FUNC(double) _Py_dg_stdnan(int sign); -PyAPI_FUNC(double) _Py_dg_infinity(int sign); - - -#ifdef __cplusplus -} -#endif -#endif -#endif +#ifndef Py_LIMITED_API +#ifndef PY_NO_SHORT_FLOAT_REPR +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr); +PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); +PyAPI_FUNC(void) _Py_dg_freedtoa(char *s); +PyAPI_FUNC(double) _Py_dg_stdnan(int sign); +PyAPI_FUNC(double) _Py_dg_infinity(int sign); + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/libs/nxpy/include/dynamic_annotations.h b/libs/nxpy/include/dynamic_annotations.h index 0bd1a833..03448a2d 100644 --- a/libs/nxpy/include/dynamic_annotations.h +++ b/libs/nxpy/include/dynamic_annotations.h @@ -1,499 +1,499 @@ -/* Copyright (c) 2008-2009, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Kostya Serebryany - * Copied to CPython by Jeffrey Yasskin, with all macros renamed to - * start with _Py_ to avoid colliding with users embedding Python, and - * with deprecated macros removed. - */ - -/* This file defines dynamic annotations for use with dynamic analysis - tool such as valgrind, PIN, etc. - - Dynamic annotation is a source code annotation that affects - the generated code (that is, the annotation is not a comment). - Each such annotation is attached to a particular - instruction and/or to a particular object (address) in the program. - - The annotations that should be used by users are macros in all upper-case - (e.g., _Py_ANNOTATE_NEW_MEMORY). - - Actual implementation of these macros may differ depending on the - dynamic analysis tool being used. - - See http://code.google.com/p/data-race-test/ for more information. - - This file supports the following dynamic analysis tools: - - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). - Macros are defined empty. - - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). - Macros are defined as calls to non-inlinable empty functions - that are intercepted by Valgrind. */ - -#ifndef __DYNAMIC_ANNOTATIONS_H__ -#define __DYNAMIC_ANNOTATIONS_H__ - -#ifndef DYNAMIC_ANNOTATIONS_ENABLED -# define DYNAMIC_ANNOTATIONS_ENABLED 0 -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 - - /* ------------------------------------------------------------- - Annotations useful when implementing condition variables such as CondVar, - using conditional critical sections (Await/LockWhen) and when constructing - user-defined synchronization mechanisms. - - The annotations _Py_ANNOTATE_HAPPENS_BEFORE() and - _Py_ANNOTATE_HAPPENS_AFTER() can be used to define happens-before arcs in - user-defined synchronization mechanisms: the race detector will infer an - arc from the former to the latter when they share the same argument - pointer. - - Example 1 (reference counting): - - void Unref() { - _Py_ANNOTATE_HAPPENS_BEFORE(&refcount_); - if (AtomicDecrementByOne(&refcount_) == 0) { - _Py_ANNOTATE_HAPPENS_AFTER(&refcount_); - delete this; - } - } - - Example 2 (message queue): - - void MyQueue::Put(Type *e) { - MutexLock lock(&mu_); - _Py_ANNOTATE_HAPPENS_BEFORE(e); - PutElementIntoMyQueue(e); - } - - Type *MyQueue::Get() { - MutexLock lock(&mu_); - Type *e = GetElementFromMyQueue(); - _Py_ANNOTATE_HAPPENS_AFTER(e); - return e; - } - - Note: when possible, please use the existing reference counting and message - queue implementations instead of inventing new ones. */ - - /* Report that wait on the condition variable at address "cv" has succeeded - and the lock at address "lock" is held. */ -#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ - AnnotateCondVarWait(__FILE__, __LINE__, cv, lock) - - /* Report that wait on the condition variable at "cv" has succeeded. Variant - w/o lock. */ -#define _Py_ANNOTATE_CONDVAR_WAIT(cv) \ - AnnotateCondVarWait(__FILE__, __LINE__, cv, NULL) - - /* Report that we are about to signal on the condition variable at address - "cv". */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) \ - AnnotateCondVarSignal(__FILE__, __LINE__, cv) - - /* Report that we are about to signal_all on the condition variable at "cv". */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ - AnnotateCondVarSignalAll(__FILE__, __LINE__, cv) - - /* Annotations for user-defined synchronization mechanisms. */ -#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) _Py_ANNOTATE_CONDVAR_SIGNAL(obj) -#define _Py_ANNOTATE_HAPPENS_AFTER(obj) _Py_ANNOTATE_CONDVAR_WAIT(obj) - - /* Report that the bytes in the range [pointer, pointer+size) are about - to be published safely. The race checker will create a happens-before - arc from the call _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to - subsequent accesses to this memory. - Note: this annotation may not work properly if the race detector uses - sampling, i.e. does not observe all memory accesses. - */ -#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ - AnnotatePublishMemoryRange(__FILE__, __LINE__, pointer, size) - - /* Instruct the tool to create a happens-before arc between mu->Unlock() and - mu->Lock(). This annotation may slow down the race detector and hide real - races. Normally it is used only when it would be difficult to annotate each - of the mutex's critical sections individually using the annotations above. - This annotation makes sense only for hybrid race detectors. For pure - happens-before detectors this is a no-op. For more details see - http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ -#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ - AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) - - /* ------------------------------------------------------------- - Annotations useful when defining memory allocators, or when memory that - was protected in one way starts to be protected in another. */ - - /* Report that a new memory at "address" of size "size" has been allocated. - This might be used when the memory has been retrieved from a free list and - is about to be reused, or when the locking discipline for a variable - changes. */ -#define _Py_ANNOTATE_NEW_MEMORY(address, size) \ - AnnotateNewMemory(__FILE__, __LINE__, address, size) - - /* ------------------------------------------------------------- - Annotations useful when defining FIFO queues that transfer data between - threads. */ - - /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at - address "pcq" has been created. The _Py_ANNOTATE_PCQ_* annotations should - be used only for FIFO queues. For non-FIFO queues use - _Py_ANNOTATE_HAPPENS_BEFORE (for put) and _Py_ANNOTATE_HAPPENS_AFTER (for - get). */ -#define _Py_ANNOTATE_PCQ_CREATE(pcq) \ - AnnotatePCQCreate(__FILE__, __LINE__, pcq) - - /* Report that the queue at address "pcq" is about to be destroyed. */ -#define _Py_ANNOTATE_PCQ_DESTROY(pcq) \ - AnnotatePCQDestroy(__FILE__, __LINE__, pcq) - - /* Report that we are about to put an element into a FIFO queue at address - "pcq". */ -#define _Py_ANNOTATE_PCQ_PUT(pcq) \ - AnnotatePCQPut(__FILE__, __LINE__, pcq) - - /* Report that we've just got an element from a FIFO queue at address "pcq". */ -#define _Py_ANNOTATE_PCQ_GET(pcq) \ - AnnotatePCQGet(__FILE__, __LINE__, pcq) - - /* ------------------------------------------------------------- - Annotations that suppress errors. It is usually better to express the - program's synchronization using the other annotations, but these can - be used when all else fails. */ - - /* Report that we may have a benign race at "pointer", with size - "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the - point where "pointer" has been allocated, preferably close to the point - where the race happens. See also _Py_ANNOTATE_BENIGN_RACE_STATIC. */ -#define _Py_ANNOTATE_BENIGN_RACE(pointer, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ - sizeof(*(pointer)), description) - - /* Same as _Py_ANNOTATE_BENIGN_RACE(address, description), but applies to - the memory range [address, address+size). */ -#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) - - /* Request the analysis tool to ignore all reads in the current thread - until _Py_ANNOTATE_IGNORE_READS_END is called. - Useful to ignore intentional racey reads, while still checking - other reads and all writes. - See also _Py_ANNOTATE_UNPROTECTED_READ. */ -#define _Py_ANNOTATE_IGNORE_READS_BEGIN() \ - AnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - /* Stop ignoring reads. */ -#define _Py_ANNOTATE_IGNORE_READS_END() \ - AnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ -#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() \ - AnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - /* Stop ignoring writes. */ -#define _Py_ANNOTATE_IGNORE_WRITES_END() \ - AnnotateIgnoreWritesEnd(__FILE__, __LINE__) - - /* Start ignoring all memory accesses (reads and writes). */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ - do {\ - _Py_ANNOTATE_IGNORE_READS_BEGIN();\ - _Py_ANNOTATE_IGNORE_WRITES_BEGIN();\ - }while(0)\ - - /* Stop ignoring all memory accesses. */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ - do {\ - _Py_ANNOTATE_IGNORE_WRITES_END();\ - _Py_ANNOTATE_IGNORE_READS_END();\ - }while(0)\ - - /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events: - RWLOCK* and CONDVAR*. */ -#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() \ - AnnotateIgnoreSyncBegin(__FILE__, __LINE__) - - /* Stop ignoring sync events. */ -#define _Py_ANNOTATE_IGNORE_SYNC_END() \ - AnnotateIgnoreSyncEnd(__FILE__, __LINE__) - - - /* Enable (enable!=0) or disable (enable==0) race detection for all threads. - This annotation could be useful if you want to skip expensive race analysis - during some period of program execution, e.g. during initialization. */ -#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ - AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) - - /* ------------------------------------------------------------- - Annotations useful for debugging. */ - - /* Request to trace every access to "address". */ -#define _Py_ANNOTATE_TRACE_MEMORY(address) \ - AnnotateTraceMemory(__FILE__, __LINE__, address) - - /* Report the current thread name to a race detector. */ -#define _Py_ANNOTATE_THREAD_NAME(name) \ - AnnotateThreadName(__FILE__, __LINE__, name) - - /* ------------------------------------------------------------- - Annotations useful when implementing locks. They are not - normally needed by modules that merely use locks. - The "lock" argument is a pointer to the lock object. */ - - /* Report that a lock has been created at address "lock". */ -#define _Py_ANNOTATE_RWLOCK_CREATE(lock) \ - AnnotateRWLockCreate(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" is about to be destroyed. */ -#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) \ - AnnotateRWLockDestroy(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" has been acquired. - is_w=1 for writer lock, is_w=0 for reader lock. */ -#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ - AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) - - /* Report that the lock at address "lock" is about to be released. */ -#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ - AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) - - /* ------------------------------------------------------------- - Annotations useful when implementing barriers. They are not - normally needed by modules that merely use barriers. - The "barrier" argument is a pointer to the barrier object. */ - - /* Report that the "barrier" has been initialized with initial "count". - If 'reinitialization_allowed' is true, initialization is allowed to happen - multiple times w/o calling barrier_destroy() */ -#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ - AnnotateBarrierInit(__FILE__, __LINE__, barrier, count, \ - reinitialization_allowed) - - /* Report that we are about to enter barrier_wait("barrier"). */ -#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ - AnnotateBarrierWaitBefore(__FILE__, __LINE__, barrier) - - /* Report that we just exited barrier_wait("barrier"). */ -#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ - AnnotateBarrierWaitAfter(__FILE__, __LINE__, barrier) - - /* Report that the "barrier" has been destroyed. */ -#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) \ - AnnotateBarrierDestroy(__FILE__, __LINE__, barrier) - - /* ------------------------------------------------------------- - Annotations useful for testing race detectors. */ - - /* Report that we expect a race on the variable at "address". - Use only in unit tests for a race detector. */ -#define _Py_ANNOTATE_EXPECT_RACE(address, description) \ - AnnotateExpectRace(__FILE__, __LINE__, address, description) - - /* A no-op. Insert where you like to test the interceptors. */ -#define _Py_ANNOTATE_NO_OP(arg) \ - AnnotateNoOp(__FILE__, __LINE__, arg) - - /* Force the race detector to flush its state. The actual effect depends on - * the implementation of the detector. */ -#define _Py_ANNOTATE_FLUSH_STATE() \ - AnnotateFlushState(__FILE__, __LINE__) - - -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - -#define _Py_ANNOTATE_RWLOCK_CREATE(lock) /* empty */ -#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ -#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ -#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ -#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ -#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ -#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ -#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ -#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ -#define _Py_ANNOTATE_CONDVAR_WAIT(cv) /* empty */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ -#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ -#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ -#define _Py_ANNOTATE_HAPPENS_AFTER(obj) /* empty */ -#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ -#define _Py_ANNOTATE_PCQ_CREATE(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_DESTROY(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_PUT(pcq) /* empty */ -#define _Py_ANNOTATE_PCQ_GET(pcq) /* empty */ -#define _Py_ANNOTATE_NEW_MEMORY(address, size) /* empty */ -#define _Py_ANNOTATE_EXPECT_RACE(address, description) /* empty */ -#define _Py_ANNOTATE_BENIGN_RACE(address, description) /* empty */ -#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ -#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ -#define _Py_ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ -#define _Py_ANNOTATE_TRACE_MEMORY(arg) /* empty */ -#define _Py_ANNOTATE_THREAD_NAME(name) /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_WRITES_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ -#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */ -#define _Py_ANNOTATE_IGNORE_SYNC_END() /* empty */ -#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ -#define _Py_ANNOTATE_NO_OP(arg) /* empty */ -#define _Py_ANNOTATE_FLUSH_STATE() /* empty */ - -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -/* Use the macros above rather than using these functions directly. */ -#ifdef __cplusplus -extern "C" { -#endif -void AnnotateRWLockCreate(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockDestroy(const char *file, int line, - const volatile void *lock); -void AnnotateRWLockAcquired(const char *file, int line, - const volatile void *lock, long is_w); -void AnnotateRWLockReleased(const char *file, int line, - const volatile void *lock, long is_w); -void AnnotateBarrierInit(const char *file, int line, - const volatile void *barrier, long count, - long reinitialization_allowed); -void AnnotateBarrierWaitBefore(const char *file, int line, - const volatile void *barrier); -void AnnotateBarrierWaitAfter(const char *file, int line, - const volatile void *barrier); -void AnnotateBarrierDestroy(const char *file, int line, - const volatile void *barrier); -void AnnotateCondVarWait(const char *file, int line, - const volatile void *cv, - const volatile void *lock); -void AnnotateCondVarSignal(const char *file, int line, - const volatile void *cv); -void AnnotateCondVarSignalAll(const char *file, int line, - const volatile void *cv); -void AnnotatePublishMemoryRange(const char *file, int line, - const volatile void *address, - long size); -void AnnotateUnpublishMemoryRange(const char *file, int line, - const volatile void *address, - long size); -void AnnotatePCQCreate(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQDestroy(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQPut(const char *file, int line, - const volatile void *pcq); -void AnnotatePCQGet(const char *file, int line, - const volatile void *pcq); -void AnnotateNewMemory(const char *file, int line, - const volatile void *address, - long size); -void AnnotateExpectRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRace(const char *file, int line, - const volatile void *address, - const char *description); -void AnnotateBenignRaceSized(const char *file, int line, - const volatile void *address, - long size, - const char *description); -void AnnotateMutexIsUsedAsCondVar(const char *file, int line, - const volatile void *mu); -void AnnotateTraceMemory(const char *file, int line, - const volatile void *arg); -void AnnotateThreadName(const char *file, int line, - const char *name); -void AnnotateIgnoreReadsBegin(const char *file, int line); -void AnnotateIgnoreReadsEnd(const char *file, int line); -void AnnotateIgnoreWritesBegin(const char *file, int line); -void AnnotateIgnoreWritesEnd(const char *file, int line); -void AnnotateEnableRaceDetection(const char *file, int line, int enable); -void AnnotateNoOp(const char *file, int line, - const volatile void *arg); -void AnnotateFlushState(const char *file, int line); - -/* Return non-zero value if running under valgrind. - - If "valgrind.h" is included into dynamic_annotations.c, - the regular valgrind mechanism will be used. - See http://valgrind.org/docs/manual/manual-core-adv.html about - RUNNING_ON_VALGRIND and other valgrind "client requests". - The file "valgrind.h" may be obtained by doing - svn co svn://svn.valgrind.org/valgrind/trunk/include - - If for some reason you can't use "valgrind.h" or want to fake valgrind, - there are two ways to make this function return non-zero: - - Use environment variable: export RUNNING_ON_VALGRIND=1 - - Make your tool intercept the function RunningOnValgrind() and - change its return value. - */ -int RunningOnValgrind(void); - -#ifdef __cplusplus -} -#endif - -#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) - - /* _Py_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. - - Instead of doing - _Py_ANNOTATE_IGNORE_READS_BEGIN(); - ... = x; - _Py_ANNOTATE_IGNORE_READS_END(); - one can use - ... = _Py_ANNOTATE_UNPROTECTED_READ(x); */ - template - inline T _Py_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { - _Py_ANNOTATE_IGNORE_READS_BEGIN(); - T res = x; - _Py_ANNOTATE_IGNORE_READS_END(); - return res; - } - /* Apply _Py_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ -#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ - namespace { \ - class static_var ## _annotator { \ - public: \ - static_var ## _annotator() { \ - _Py_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ - sizeof(static_var), \ - # static_var ": " description); \ - } \ - }; \ - static static_var ## _annotator the ## static_var ## _annotator;\ - } -#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - -#define _Py_ANNOTATE_UNPROTECTED_READ(x) (x) -#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ - -#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ - -#endif /* __DYNAMIC_ANNOTATIONS_H__ */ +/* Copyright (c) 2008-2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * --- + * Author: Kostya Serebryany + * Copied to CPython by Jeffrey Yasskin, with all macros renamed to + * start with _Py_ to avoid colliding with users embedding Python, and + * with deprecated macros removed. + */ + +/* This file defines dynamic annotations for use with dynamic analysis + tool such as valgrind, PIN, etc. + + Dynamic annotation is a source code annotation that affects + the generated code (that is, the annotation is not a comment). + Each such annotation is attached to a particular + instruction and/or to a particular object (address) in the program. + + The annotations that should be used by users are macros in all upper-case + (e.g., _Py_ANNOTATE_NEW_MEMORY). + + Actual implementation of these macros may differ depending on the + dynamic analysis tool being used. + + See http://code.google.com/p/data-race-test/ for more information. + + This file supports the following dynamic analysis tools: + - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). + Macros are defined empty. + - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). + Macros are defined as calls to non-inlinable empty functions + that are intercepted by Valgrind. */ + +#ifndef __DYNAMIC_ANNOTATIONS_H__ +#define __DYNAMIC_ANNOTATIONS_H__ + +#ifndef DYNAMIC_ANNOTATIONS_ENABLED +# define DYNAMIC_ANNOTATIONS_ENABLED 0 +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 + + /* ------------------------------------------------------------- + Annotations useful when implementing condition variables such as CondVar, + using conditional critical sections (Await/LockWhen) and when constructing + user-defined synchronization mechanisms. + + The annotations _Py_ANNOTATE_HAPPENS_BEFORE() and + _Py_ANNOTATE_HAPPENS_AFTER() can be used to define happens-before arcs in + user-defined synchronization mechanisms: the race detector will infer an + arc from the former to the latter when they share the same argument + pointer. + + Example 1 (reference counting): + + void Unref() { + _Py_ANNOTATE_HAPPENS_BEFORE(&refcount_); + if (AtomicDecrementByOne(&refcount_) == 0) { + _Py_ANNOTATE_HAPPENS_AFTER(&refcount_); + delete this; + } + } + + Example 2 (message queue): + + void MyQueue::Put(Type *e) { + MutexLock lock(&mu_); + _Py_ANNOTATE_HAPPENS_BEFORE(e); + PutElementIntoMyQueue(e); + } + + Type *MyQueue::Get() { + MutexLock lock(&mu_); + Type *e = GetElementFromMyQueue(); + _Py_ANNOTATE_HAPPENS_AFTER(e); + return e; + } + + Note: when possible, please use the existing reference counting and message + queue implementations instead of inventing new ones. */ + + /* Report that wait on the condition variable at address "cv" has succeeded + and the lock at address "lock" is held. */ +#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ + AnnotateCondVarWait(__FILE__, __LINE__, cv, lock) + + /* Report that wait on the condition variable at "cv" has succeeded. Variant + w/o lock. */ +#define _Py_ANNOTATE_CONDVAR_WAIT(cv) \ + AnnotateCondVarWait(__FILE__, __LINE__, cv, NULL) + + /* Report that we are about to signal on the condition variable at address + "cv". */ +#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) \ + AnnotateCondVarSignal(__FILE__, __LINE__, cv) + + /* Report that we are about to signal_all on the condition variable at "cv". */ +#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ + AnnotateCondVarSignalAll(__FILE__, __LINE__, cv) + + /* Annotations for user-defined synchronization mechanisms. */ +#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) _Py_ANNOTATE_CONDVAR_SIGNAL(obj) +#define _Py_ANNOTATE_HAPPENS_AFTER(obj) _Py_ANNOTATE_CONDVAR_WAIT(obj) + + /* Report that the bytes in the range [pointer, pointer+size) are about + to be published safely. The race checker will create a happens-before + arc from the call _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to + subsequent accesses to this memory. + Note: this annotation may not work properly if the race detector uses + sampling, i.e. does not observe all memory accesses. + */ +#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ + AnnotatePublishMemoryRange(__FILE__, __LINE__, pointer, size) + + /* Instruct the tool to create a happens-before arc between mu->Unlock() and + mu->Lock(). This annotation may slow down the race detector and hide real + races. Normally it is used only when it would be difficult to annotate each + of the mutex's critical sections individually using the annotations above. + This annotation makes sense only for hybrid race detectors. For pure + happens-before detectors this is a no-op. For more details see + http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ +#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ + AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) + + /* ------------------------------------------------------------- + Annotations useful when defining memory allocators, or when memory that + was protected in one way starts to be protected in another. */ + + /* Report that a new memory at "address" of size "size" has been allocated. + This might be used when the memory has been retrieved from a free list and + is about to be reused, or when the locking discipline for a variable + changes. */ +#define _Py_ANNOTATE_NEW_MEMORY(address, size) \ + AnnotateNewMemory(__FILE__, __LINE__, address, size) + + /* ------------------------------------------------------------- + Annotations useful when defining FIFO queues that transfer data between + threads. */ + + /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at + address "pcq" has been created. The _Py_ANNOTATE_PCQ_* annotations should + be used only for FIFO queues. For non-FIFO queues use + _Py_ANNOTATE_HAPPENS_BEFORE (for put) and _Py_ANNOTATE_HAPPENS_AFTER (for + get). */ +#define _Py_ANNOTATE_PCQ_CREATE(pcq) \ + AnnotatePCQCreate(__FILE__, __LINE__, pcq) + + /* Report that the queue at address "pcq" is about to be destroyed. */ +#define _Py_ANNOTATE_PCQ_DESTROY(pcq) \ + AnnotatePCQDestroy(__FILE__, __LINE__, pcq) + + /* Report that we are about to put an element into a FIFO queue at address + "pcq". */ +#define _Py_ANNOTATE_PCQ_PUT(pcq) \ + AnnotatePCQPut(__FILE__, __LINE__, pcq) + + /* Report that we've just got an element from a FIFO queue at address "pcq". */ +#define _Py_ANNOTATE_PCQ_GET(pcq) \ + AnnotatePCQGet(__FILE__, __LINE__, pcq) + + /* ------------------------------------------------------------- + Annotations that suppress errors. It is usually better to express the + program's synchronization using the other annotations, but these can + be used when all else fails. */ + + /* Report that we may have a benign race at "pointer", with size + "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the + point where "pointer" has been allocated, preferably close to the point + where the race happens. See also _Py_ANNOTATE_BENIGN_RACE_STATIC. */ +#define _Py_ANNOTATE_BENIGN_RACE(pointer, description) \ + AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ + sizeof(*(pointer)), description) + + /* Same as _Py_ANNOTATE_BENIGN_RACE(address, description), but applies to + the memory range [address, address+size). */ +#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + AnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) + + /* Request the analysis tool to ignore all reads in the current thread + until _Py_ANNOTATE_IGNORE_READS_END is called. + Useful to ignore intentional racey reads, while still checking + other reads and all writes. + See also _Py_ANNOTATE_UNPROTECTED_READ. */ +#define _Py_ANNOTATE_IGNORE_READS_BEGIN() \ + AnnotateIgnoreReadsBegin(__FILE__, __LINE__) + + /* Stop ignoring reads. */ +#define _Py_ANNOTATE_IGNORE_READS_END() \ + AnnotateIgnoreReadsEnd(__FILE__, __LINE__) + + /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ +#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() \ + AnnotateIgnoreWritesBegin(__FILE__, __LINE__) + + /* Stop ignoring writes. */ +#define _Py_ANNOTATE_IGNORE_WRITES_END() \ + AnnotateIgnoreWritesEnd(__FILE__, __LINE__) + + /* Start ignoring all memory accesses (reads and writes). */ +#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do {\ + _Py_ANNOTATE_IGNORE_READS_BEGIN();\ + _Py_ANNOTATE_IGNORE_WRITES_BEGIN();\ + }while(0)\ + + /* Stop ignoring all memory accesses. */ +#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do {\ + _Py_ANNOTATE_IGNORE_WRITES_END();\ + _Py_ANNOTATE_IGNORE_READS_END();\ + }while(0)\ + + /* Similar to _Py_ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events: + RWLOCK* and CONDVAR*. */ +#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() \ + AnnotateIgnoreSyncBegin(__FILE__, __LINE__) + + /* Stop ignoring sync events. */ +#define _Py_ANNOTATE_IGNORE_SYNC_END() \ + AnnotateIgnoreSyncEnd(__FILE__, __LINE__) + + + /* Enable (enable!=0) or disable (enable==0) race detection for all threads. + This annotation could be useful if you want to skip expensive race analysis + during some period of program execution, e.g. during initialization. */ +#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + AnnotateEnableRaceDetection(__FILE__, __LINE__, enable) + + /* ------------------------------------------------------------- + Annotations useful for debugging. */ + + /* Request to trace every access to "address". */ +#define _Py_ANNOTATE_TRACE_MEMORY(address) \ + AnnotateTraceMemory(__FILE__, __LINE__, address) + + /* Report the current thread name to a race detector. */ +#define _Py_ANNOTATE_THREAD_NAME(name) \ + AnnotateThreadName(__FILE__, __LINE__, name) + + /* ------------------------------------------------------------- + Annotations useful when implementing locks. They are not + normally needed by modules that merely use locks. + The "lock" argument is a pointer to the lock object. */ + + /* Report that a lock has been created at address "lock". */ +#define _Py_ANNOTATE_RWLOCK_CREATE(lock) \ + AnnotateRWLockCreate(__FILE__, __LINE__, lock) + + /* Report that the lock at address "lock" is about to be destroyed. */ +#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) \ + AnnotateRWLockDestroy(__FILE__, __LINE__, lock) + + /* Report that the lock at address "lock" has been acquired. + is_w=1 for writer lock, is_w=0 for reader lock. */ +#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) + + /* Report that the lock at address "lock" is about to be released. */ +#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) + + /* ------------------------------------------------------------- + Annotations useful when implementing barriers. They are not + normally needed by modules that merely use barriers. + The "barrier" argument is a pointer to the barrier object. */ + + /* Report that the "barrier" has been initialized with initial "count". + If 'reinitialization_allowed' is true, initialization is allowed to happen + multiple times w/o calling barrier_destroy() */ +#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ + AnnotateBarrierInit(__FILE__, __LINE__, barrier, count, \ + reinitialization_allowed) + + /* Report that we are about to enter barrier_wait("barrier"). */ +#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ + AnnotateBarrierWaitBefore(__FILE__, __LINE__, barrier) + + /* Report that we just exited barrier_wait("barrier"). */ +#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ + AnnotateBarrierWaitAfter(__FILE__, __LINE__, barrier) + + /* Report that the "barrier" has been destroyed. */ +#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) \ + AnnotateBarrierDestroy(__FILE__, __LINE__, barrier) + + /* ------------------------------------------------------------- + Annotations useful for testing race detectors. */ + + /* Report that we expect a race on the variable at "address". + Use only in unit tests for a race detector. */ +#define _Py_ANNOTATE_EXPECT_RACE(address, description) \ + AnnotateExpectRace(__FILE__, __LINE__, address, description) + + /* A no-op. Insert where you like to test the interceptors. */ +#define _Py_ANNOTATE_NO_OP(arg) \ + AnnotateNoOp(__FILE__, __LINE__, arg) + + /* Force the race detector to flush its state. The actual effect depends on + * the implementation of the detector. */ +#define _Py_ANNOTATE_FLUSH_STATE() \ + AnnotateFlushState(__FILE__, __LINE__) + + +#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ + +#define _Py_ANNOTATE_RWLOCK_CREATE(lock) /* empty */ +#define _Py_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ +#define _Py_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ +#define _Py_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ +#define _Py_ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ +#define _Py_ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ +#define _Py_ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ +#define _Py_ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ +#define _Py_ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ +#define _Py_ANNOTATE_CONDVAR_WAIT(cv) /* empty */ +#define _Py_ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ +#define _Py_ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ +#define _Py_ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ +#define _Py_ANNOTATE_HAPPENS_AFTER(obj) /* empty */ +#define _Py_ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ +#define _Py_ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ +#define _Py_ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ +#define _Py_ANNOTATE_PCQ_CREATE(pcq) /* empty */ +#define _Py_ANNOTATE_PCQ_DESTROY(pcq) /* empty */ +#define _Py_ANNOTATE_PCQ_PUT(pcq) /* empty */ +#define _Py_ANNOTATE_PCQ_GET(pcq) /* empty */ +#define _Py_ANNOTATE_NEW_MEMORY(address, size) /* empty */ +#define _Py_ANNOTATE_EXPECT_RACE(address, description) /* empty */ +#define _Py_ANNOTATE_BENIGN_RACE(address, description) /* empty */ +#define _Py_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ +#define _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ +#define _Py_ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ +#define _Py_ANNOTATE_TRACE_MEMORY(arg) /* empty */ +#define _Py_ANNOTATE_THREAD_NAME(name) /* empty */ +#define _Py_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ +#define _Py_ANNOTATE_IGNORE_READS_END() /* empty */ +#define _Py_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ +#define _Py_ANNOTATE_IGNORE_WRITES_END() /* empty */ +#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ +#define _Py_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ +#define _Py_ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */ +#define _Py_ANNOTATE_IGNORE_SYNC_END() /* empty */ +#define _Py_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ +#define _Py_ANNOTATE_NO_OP(arg) /* empty */ +#define _Py_ANNOTATE_FLUSH_STATE() /* empty */ + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ + +/* Use the macros above rather than using these functions directly. */ +#ifdef __cplusplus +extern "C" { +#endif +void AnnotateRWLockCreate(const char *file, int line, + const volatile void *lock); +void AnnotateRWLockDestroy(const char *file, int line, + const volatile void *lock); +void AnnotateRWLockAcquired(const char *file, int line, + const volatile void *lock, long is_w); +void AnnotateRWLockReleased(const char *file, int line, + const volatile void *lock, long is_w); +void AnnotateBarrierInit(const char *file, int line, + const volatile void *barrier, long count, + long reinitialization_allowed); +void AnnotateBarrierWaitBefore(const char *file, int line, + const volatile void *barrier); +void AnnotateBarrierWaitAfter(const char *file, int line, + const volatile void *barrier); +void AnnotateBarrierDestroy(const char *file, int line, + const volatile void *barrier); +void AnnotateCondVarWait(const char *file, int line, + const volatile void *cv, + const volatile void *lock); +void AnnotateCondVarSignal(const char *file, int line, + const volatile void *cv); +void AnnotateCondVarSignalAll(const char *file, int line, + const volatile void *cv); +void AnnotatePublishMemoryRange(const char *file, int line, + const volatile void *address, + long size); +void AnnotateUnpublishMemoryRange(const char *file, int line, + const volatile void *address, + long size); +void AnnotatePCQCreate(const char *file, int line, + const volatile void *pcq); +void AnnotatePCQDestroy(const char *file, int line, + const volatile void *pcq); +void AnnotatePCQPut(const char *file, int line, + const volatile void *pcq); +void AnnotatePCQGet(const char *file, int line, + const volatile void *pcq); +void AnnotateNewMemory(const char *file, int line, + const volatile void *address, + long size); +void AnnotateExpectRace(const char *file, int line, + const volatile void *address, + const char *description); +void AnnotateBenignRace(const char *file, int line, + const volatile void *address, + const char *description); +void AnnotateBenignRaceSized(const char *file, int line, + const volatile void *address, + long size, + const char *description); +void AnnotateMutexIsUsedAsCondVar(const char *file, int line, + const volatile void *mu); +void AnnotateTraceMemory(const char *file, int line, + const volatile void *arg); +void AnnotateThreadName(const char *file, int line, + const char *name); +void AnnotateIgnoreReadsBegin(const char *file, int line); +void AnnotateIgnoreReadsEnd(const char *file, int line); +void AnnotateIgnoreWritesBegin(const char *file, int line); +void AnnotateIgnoreWritesEnd(const char *file, int line); +void AnnotateEnableRaceDetection(const char *file, int line, int enable); +void AnnotateNoOp(const char *file, int line, + const volatile void *arg); +void AnnotateFlushState(const char *file, int line); + +/* Return non-zero value if running under valgrind. + + If "valgrind.h" is included into dynamic_annotations.c, + the regular valgrind mechanism will be used. + See http://valgrind.org/docs/manual/manual-core-adv.html about + RUNNING_ON_VALGRIND and other valgrind "client requests". + The file "valgrind.h" may be obtained by doing + svn co svn://svn.valgrind.org/valgrind/trunk/include + + If for some reason you can't use "valgrind.h" or want to fake valgrind, + there are two ways to make this function return non-zero: + - Use environment variable: export RUNNING_ON_VALGRIND=1 + - Make your tool intercept the function RunningOnValgrind() and + change its return value. + */ +int RunningOnValgrind(void); + +#ifdef __cplusplus +} +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) + + /* _Py_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. + + Instead of doing + _Py_ANNOTATE_IGNORE_READS_BEGIN(); + ... = x; + _Py_ANNOTATE_IGNORE_READS_END(); + one can use + ... = _Py_ANNOTATE_UNPROTECTED_READ(x); */ + template + inline T _Py_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { + _Py_ANNOTATE_IGNORE_READS_BEGIN(); + T res = x; + _Py_ANNOTATE_IGNORE_READS_END(); + return res; + } + /* Apply _Py_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ +#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var ## _annotator { \ + public: \ + static_var ## _annotator() { \ + _Py_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ + sizeof(static_var), \ + # static_var ": " description); \ + } \ + }; \ + static static_var ## _annotator the ## static_var ## _annotator;\ + } +#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ + +#define _Py_ANNOTATE_UNPROTECTED_READ(x) (x) +#define _Py_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ + +#endif /* __DYNAMIC_ANNOTATIONS_H__ */ diff --git a/libs/nxpy/include/enumobject.h b/libs/nxpy/include/enumobject.h index c14dbfc8..42dc2d27 100644 --- a/libs/nxpy/include/enumobject.h +++ b/libs/nxpy/include/enumobject.h @@ -1,17 +1,17 @@ -#ifndef Py_ENUMOBJECT_H -#define Py_ENUMOBJECT_H - -/* Enumerate Object */ - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyEnum_Type; -PyAPI_DATA(PyTypeObject) PyReversed_Type; - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_ENUMOBJECT_H */ +#ifndef Py_ENUMOBJECT_H +#define Py_ENUMOBJECT_H + +/* Enumerate Object */ + +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyEnum_Type; +PyAPI_DATA(PyTypeObject) PyReversed_Type; + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_ENUMOBJECT_H */ diff --git a/libs/nxpy/include/errcode.h b/libs/nxpy/include/errcode.h index 5946686c..c469a8cd 100644 --- a/libs/nxpy/include/errcode.h +++ b/libs/nxpy/include/errcode.h @@ -1,38 +1,38 @@ -#ifndef Py_ERRCODE_H -#define Py_ERRCODE_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Error codes passed around between file input, tokenizer, parser and - interpreter. This is necessary so we can turn them into Python - exceptions at a higher level. Note that some errors have a - slightly different meaning when passed from the tokenizer to the - parser than when passed from the parser to the interpreter; e.g. - the parser only returns E_EOF when it hits EOF immediately, and it - never returns E_OK. */ - -#define E_OK 10 /* No error */ -#define E_EOF 11 /* End Of File */ -#define E_INTR 12 /* Interrupted */ -#define E_TOKEN 13 /* Bad token */ -#define E_SYNTAX 14 /* Syntax error */ -#define E_NOMEM 15 /* Ran out of memory */ -#define E_DONE 16 /* Parsing complete */ -#define E_ERROR 17 /* Execution error */ -#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ -#define E_OVERFLOW 19 /* Node had too many children */ -#define E_TOODEEP 20 /* Too many indentation levels */ -#define E_DEDENT 21 /* No matching outer block for dedent */ -#define E_DECODE 22 /* Error in decoding into Unicode */ -#define E_EOFS 23 /* EOF in triple-quoted string */ -#define E_EOLS 24 /* EOL in single-quoted string */ -#define E_LINECONT 25 /* Unexpected characters after a line continuation */ -#define E_IDENTIFIER 26 /* Invalid characters in identifier */ -#define E_BADSINGLE 27 /* Ill-formed single statement input */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ERRCODE_H */ +#ifndef Py_ERRCODE_H +#define Py_ERRCODE_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Error codes passed around between file input, tokenizer, parser and + interpreter. This is necessary so we can turn them into Python + exceptions at a higher level. Note that some errors have a + slightly different meaning when passed from the tokenizer to the + parser than when passed from the parser to the interpreter; e.g. + the parser only returns E_EOF when it hits EOF immediately, and it + never returns E_OK. */ + +#define E_OK 10 /* No error */ +#define E_EOF 11 /* End Of File */ +#define E_INTR 12 /* Interrupted */ +#define E_TOKEN 13 /* Bad token */ +#define E_SYNTAX 14 /* Syntax error */ +#define E_NOMEM 15 /* Ran out of memory */ +#define E_DONE 16 /* Parsing complete */ +#define E_ERROR 17 /* Execution error */ +#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ +#define E_OVERFLOW 19 /* Node had too many children */ +#define E_TOODEEP 20 /* Too many indentation levels */ +#define E_DEDENT 21 /* No matching outer block for dedent */ +#define E_DECODE 22 /* Error in decoding into Unicode */ +#define E_EOFS 23 /* EOF in triple-quoted string */ +#define E_EOLS 24 /* EOL in single-quoted string */ +#define E_LINECONT 25 /* Unexpected characters after a line continuation */ +#define E_IDENTIFIER 26 /* Invalid characters in identifier */ +#define E_BADSINGLE 27 /* Ill-formed single statement input */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ERRCODE_H */ diff --git a/libs/nxpy/include/eval.h b/libs/nxpy/include/eval.h index a1c6e817..4320cd71 100644 --- a/libs/nxpy/include/eval.h +++ b/libs/nxpy/include/eval.h @@ -1,27 +1,27 @@ - -/* Interface to execute compiled code */ - -#ifndef Py_EVAL_H -#define Py_EVAL_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *); - -PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co, - PyObject *globals, - PyObject *locals, - PyObject **args, int argc, - PyObject **kwds, int kwdc, - PyObject **defs, int defc, - PyObject *kwdefs, PyObject *closure); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_EVAL_H */ + +/* Interface to execute compiled code */ + +#ifndef Py_EVAL_H +#define Py_EVAL_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *); + +PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co, + PyObject *globals, + PyObject *locals, + PyObject **args, int argc, + PyObject **kwds, int kwdc, + PyObject **defs, int defc, + PyObject *kwdefs, PyObject *closure); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_EVAL_H */ diff --git a/libs/nxpy/include/fileobject.h b/libs/nxpy/include/fileobject.h index 03155d3d..6ad0b1ee 100644 --- a/libs/nxpy/include/fileobject.h +++ b/libs/nxpy/include/fileobject.h @@ -1,47 +1,47 @@ -/* File object interface (what's left of it -- see io.py) */ - -#ifndef Py_FILEOBJECT_H -#define Py_FILEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#define PY_STDIOTEXTMODE "b" - -PyAPI_FUNC(PyObject *) PyFile_FromFd(int, const char *, const char *, int, - const char *, const char *, - const char *, int); -PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int); -PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); -PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); -PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); -#endif - -/* The default encoding used by the platform file system APIs - If non-NULL, this is different than the default encoding for strings -*/ -PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; -PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; - -/* Internal API - - The std printer acts as a preliminary sys.stderr until the new io - infrastructure is in place. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int); -PyAPI_DATA(PyTypeObject) PyStdPrinter_Type; -#endif /* Py_LIMITED_API */ - -/* A routine to check if a file descriptor can be select()-ed. */ -#ifdef HAVE_SELECT - #define _PyIsSelectable_fd(FD) (((FD) >= 0) && ((FD) < FD_SETSIZE)) -#else - #define _PyIsSelectable_fd(FD) (1) -#endif /* HAVE_SELECT */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FILEOBJECT_H */ +/* File object interface (what's left of it -- see io.py) */ + +#ifndef Py_FILEOBJECT_H +#define Py_FILEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define PY_STDIOTEXTMODE "b" + +PyAPI_FUNC(PyObject *) PyFile_FromFd(int, const char *, const char *, int, + const char *, const char *, + const char *, int); +PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int); +PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); +PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); +PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); +#endif + +/* The default encoding used by the platform file system APIs + If non-NULL, this is different than the default encoding for strings +*/ +PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; +PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; + +/* Internal API + + The std printer acts as a preliminary sys.stderr until the new io + infrastructure is in place. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int); +PyAPI_DATA(PyTypeObject) PyStdPrinter_Type; +#endif /* Py_LIMITED_API */ + +/* A routine to check if a file descriptor can be select()-ed. */ +#ifdef HAVE_SELECT + #define _PyIsSelectable_fd(FD) (((FD) >= 0) && ((FD) < FD_SETSIZE)) +#else + #define _PyIsSelectable_fd(FD) (1) +#endif /* HAVE_SELECT */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FILEOBJECT_H */ diff --git a/libs/nxpy/include/fileutils.h b/libs/nxpy/include/fileutils.h index b4a683c1..0e05f040 100644 --- a/libs/nxpy/include/fileutils.h +++ b/libs/nxpy/include/fileutils.h @@ -1,142 +1,142 @@ -#ifndef Py_FILEUTILS_H -#define Py_FILEUTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) _Py_device_encoding(int); - -PyAPI_FUNC(wchar_t *) Py_DecodeLocale( - const char *arg, - size_t *size); - -PyAPI_FUNC(char*) Py_EncodeLocale( - const wchar_t *text, - size_t *error_pos); - -#ifndef Py_LIMITED_API - -#ifdef MS_WINDOWS -struct _Py_stat_struct { - unsigned long st_dev; - __int64 st_ino; - unsigned short st_mode; - int st_nlink; - int st_uid; - int st_gid; - unsigned long st_rdev; - __int64 st_size; - time_t st_atime; - int st_atime_nsec; - time_t st_mtime; - int st_mtime_nsec; - time_t st_ctime; - int st_ctime_nsec; - unsigned long st_file_attributes; -}; -#else -# define _Py_stat_struct stat -#endif - -PyAPI_FUNC(int) _Py_fstat( - int fd, - struct _Py_stat_struct *status); - -PyAPI_FUNC(int) _Py_fstat_noraise( - int fd, - struct _Py_stat_struct *status); -#endif /* Py_LIMITED_API */ - -PyAPI_FUNC(int) _Py_stat( - PyObject *path, - struct stat *status); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _Py_open( - const char *pathname, - int flags); - -PyAPI_FUNC(int) _Py_open_noraise( - const char *pathname, - int flags); -#endif - -PyAPI_FUNC(FILE *) _Py_wfopen( - const wchar_t *path, - const wchar_t *mode); - -PyAPI_FUNC(FILE*) _Py_fopen( - const char *pathname, - const char *mode); - -PyAPI_FUNC(FILE*) _Py_fopen_obj( - PyObject *path, - const char *mode); - -PyAPI_FUNC(Py_ssize_t) _Py_read( - int fd, - void *buf, - size_t count); - -PyAPI_FUNC(Py_ssize_t) _Py_write( - int fd, - const void *buf, - size_t count); - -PyAPI_FUNC(Py_ssize_t) _Py_write_noraise( - int fd, - const void *buf, - size_t count); - -#ifdef HAVE_READLINK -PyAPI_FUNC(int) _Py_wreadlink( - const wchar_t *path, - wchar_t *buf, - size_t bufsiz); -#endif - -#ifdef HAVE_REALPATH -PyAPI_FUNC(wchar_t*) _Py_wrealpath( - const wchar_t *path, - wchar_t *resolved_path, - size_t resolved_path_size); -#endif - -PyAPI_FUNC(wchar_t*) _Py_wgetcwd( - wchar_t *buf, - size_t size); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _Py_get_inheritable(int fd); - -PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable, - int *atomic_flag_works); - -PyAPI_FUNC(int) _Py_dup(int fd); - -#ifndef MS_WINDOWS -PyAPI_FUNC(int) _Py_get_blocking(int fd); - -PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking); -#endif /* !MS_WINDOWS */ - -#if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900 -/* A routine to check if a file descriptor is valid on Windows. Returns 0 - * and sets errno to EBADF if it isn't. This is to avoid Assertions - * from various functions in the Windows CRT beginning with - * Visual Studio 2005 - */ -int _PyVerify_fd(int fd); - -#else -#define _PyVerify_fd(A) (1) /* dummy */ -#endif - -#endif /* Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_FILEUTILS_H */ +#ifndef Py_FILEUTILS_H +#define Py_FILEUTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(PyObject *) _Py_device_encoding(int); + +PyAPI_FUNC(wchar_t *) Py_DecodeLocale( + const char *arg, + size_t *size); + +PyAPI_FUNC(char*) Py_EncodeLocale( + const wchar_t *text, + size_t *error_pos); + +#ifndef Py_LIMITED_API + +#ifdef MS_WINDOWS +struct _Py_stat_struct { + unsigned long st_dev; + __int64 st_ino; + unsigned short st_mode; + int st_nlink; + int st_uid; + int st_gid; + unsigned long st_rdev; + __int64 st_size; + time_t st_atime; + int st_atime_nsec; + time_t st_mtime; + int st_mtime_nsec; + time_t st_ctime; + int st_ctime_nsec; + unsigned long st_file_attributes; +}; +#else +# define _Py_stat_struct stat +#endif + +PyAPI_FUNC(int) _Py_fstat( + int fd, + struct _Py_stat_struct *status); + +PyAPI_FUNC(int) _Py_fstat_noraise( + int fd, + struct _Py_stat_struct *status); +#endif /* Py_LIMITED_API */ + +PyAPI_FUNC(int) _Py_stat( + PyObject *path, + struct stat *status); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _Py_open( + const char *pathname, + int flags); + +PyAPI_FUNC(int) _Py_open_noraise( + const char *pathname, + int flags); +#endif + +PyAPI_FUNC(FILE *) _Py_wfopen( + const wchar_t *path, + const wchar_t *mode); + +PyAPI_FUNC(FILE*) _Py_fopen( + const char *pathname, + const char *mode); + +PyAPI_FUNC(FILE*) _Py_fopen_obj( + PyObject *path, + const char *mode); + +PyAPI_FUNC(Py_ssize_t) _Py_read( + int fd, + void *buf, + size_t count); + +PyAPI_FUNC(Py_ssize_t) _Py_write( + int fd, + const void *buf, + size_t count); + +PyAPI_FUNC(Py_ssize_t) _Py_write_noraise( + int fd, + const void *buf, + size_t count); + +#ifdef HAVE_READLINK +PyAPI_FUNC(int) _Py_wreadlink( + const wchar_t *path, + wchar_t *buf, + size_t bufsiz); +#endif + +#ifdef HAVE_REALPATH +PyAPI_FUNC(wchar_t*) _Py_wrealpath( + const wchar_t *path, + wchar_t *resolved_path, + size_t resolved_path_size); +#endif + +PyAPI_FUNC(wchar_t*) _Py_wgetcwd( + wchar_t *buf, + size_t size); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _Py_get_inheritable(int fd); + +PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable, + int *atomic_flag_works); + +PyAPI_FUNC(int) _Py_dup(int fd); + +#ifndef MS_WINDOWS +PyAPI_FUNC(int) _Py_get_blocking(int fd); + +PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking); +#endif /* !MS_WINDOWS */ + +#if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900 +/* A routine to check if a file descriptor is valid on Windows. Returns 0 + * and sets errno to EBADF if it isn't. This is to avoid Assertions + * from various functions in the Windows CRT beginning with + * Visual Studio 2005 + */ +int _PyVerify_fd(int fd); + +#else +#define _PyVerify_fd(A) (1) /* dummy */ +#endif + +#endif /* Py_LIMITED_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_FILEUTILS_H */ diff --git a/libs/nxpy/include/floatobject.h b/libs/nxpy/include/floatobject.h index e240fdb8..047b015e 100644 --- a/libs/nxpy/include/floatobject.h +++ b/libs/nxpy/include/floatobject.h @@ -1,128 +1,128 @@ - -/* Float object interface */ - -/* -PyFloatObject represents a (double precision) floating point number. -*/ - -#ifndef Py_FLOATOBJECT_H -#define Py_FLOATOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - double ob_fval; -} PyFloatObject; -#endif - -PyAPI_DATA(PyTypeObject) PyFloat_Type; - -#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type) -#define PyFloat_CheckExact(op) (Py_TYPE(op) == &PyFloat_Type) - -#ifdef Py_NAN -#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN) -#endif - -#define Py_RETURN_INF(sign) do \ - if (copysign(1., sign) == 1.) { \ - return PyFloat_FromDouble(Py_HUGE_VAL); \ - } else { \ - return PyFloat_FromDouble(-Py_HUGE_VAL); \ - } while(0) - -PyAPI_FUNC(double) PyFloat_GetMax(void); -PyAPI_FUNC(double) PyFloat_GetMin(void); -PyAPI_FUNC(PyObject *) PyFloat_GetInfo(void); - -/* Return Python float from string PyObject. */ -PyAPI_FUNC(PyObject *) PyFloat_FromString(PyObject*); - -/* Return Python float from C double. */ -PyAPI_FUNC(PyObject *) PyFloat_FromDouble(double); - -/* Extract C double from Python float. The macro version trades safety for - speed. */ -PyAPI_FUNC(double) PyFloat_AsDouble(PyObject *); -#ifndef Py_LIMITED_API -#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval) -#endif - -#ifndef Py_LIMITED_API -/* _PyFloat_{Pack,Unpack}{4,8} - * - * The struct and pickle (at least) modules need an efficient platform- - * independent way to store floating-point values as byte strings. - * The Pack routines produce a string from a C double, and the Unpack - * routines produce a C double from such a string. The suffix (4 or 8) - * specifies the number of bytes in the string. - * - * On platforms that appear to use (see _PyFloat_Init()) IEEE-754 formats - * these functions work by copying bits. On other platforms, the formats the - * 4- byte format is identical to the IEEE-754 single precision format, and - * the 8-byte format to the IEEE-754 double precision format, although the - * packing of INFs and NaNs (if such things exist on the platform) isn't - * handled correctly, and attempting to unpack a string containing an IEEE - * INF or NaN will raise an exception. - * - * On non-IEEE platforms with more precision, or larger dynamic range, than - * 754 supports, not all values can be packed; on non-IEEE platforms with less - * precision, or smaller dynamic range, not all values can be unpacked. What - * happens in such cases is partly accidental (alas). - */ - -/* The pack routines write 4 or 8 bytes, starting at p. le is a bool - * argument, true if you want the string in little-endian format (exponent - * last, at p+3 or p+7), false if you want big-endian format (exponent - * first, at p). - * Return value: 0 if all is OK, -1 if error (and an exception is - * set, most likely OverflowError). - * There are two problems on non-IEEE platforms: - * 1): What this does is undefined if x is a NaN or infinity. - * 2): -0.0 and +0.0 produce the same string. - */ -PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); -PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); - -/* Needed for the old way for marshal to store a floating point number. - Returns the string length copied into p, -1 on error. - */ -PyAPI_FUNC(int) _PyFloat_Repr(double x, char *p, size_t len); - -/* Used to get the important decimal digits of a double */ -PyAPI_FUNC(int) _PyFloat_Digits(char *buf, double v, int *signum); -PyAPI_FUNC(void) _PyFloat_DigitsInit(void); - -/* The unpack routines read 4 or 8 bytes, starting at p. le is a bool - * argument, true if the string is in little-endian format (exponent - * last, at p+3 or p+7), false if big-endian (exponent first, at p). - * Return value: The unpacked double. On error, this is -1.0 and - * PyErr_Occurred() is true (and an exception is set, most likely - * OverflowError). Note that on a non-IEEE platform this will refuse - * to unpack a string that represents a NaN or infinity. - */ -PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); -PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); - -/* free list api */ -PyAPI_FUNC(int) PyFloat_ClearFreeList(void); - -PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out); - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyFloat_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif /* Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FLOATOBJECT_H */ + +/* Float object interface */ + +/* +PyFloatObject represents a (double precision) floating point number. +*/ + +#ifndef Py_FLOATOBJECT_H +#define Py_FLOATOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +typedef struct { + PyObject_HEAD + double ob_fval; +} PyFloatObject; +#endif + +PyAPI_DATA(PyTypeObject) PyFloat_Type; + +#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type) +#define PyFloat_CheckExact(op) (Py_TYPE(op) == &PyFloat_Type) + +#ifdef Py_NAN +#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN) +#endif + +#define Py_RETURN_INF(sign) do \ + if (copysign(1., sign) == 1.) { \ + return PyFloat_FromDouble(Py_HUGE_VAL); \ + } else { \ + return PyFloat_FromDouble(-Py_HUGE_VAL); \ + } while(0) + +PyAPI_FUNC(double) PyFloat_GetMax(void); +PyAPI_FUNC(double) PyFloat_GetMin(void); +PyAPI_FUNC(PyObject *) PyFloat_GetInfo(void); + +/* Return Python float from string PyObject. */ +PyAPI_FUNC(PyObject *) PyFloat_FromString(PyObject*); + +/* Return Python float from C double. */ +PyAPI_FUNC(PyObject *) PyFloat_FromDouble(double); + +/* Extract C double from Python float. The macro version trades safety for + speed. */ +PyAPI_FUNC(double) PyFloat_AsDouble(PyObject *); +#ifndef Py_LIMITED_API +#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval) +#endif + +#ifndef Py_LIMITED_API +/* _PyFloat_{Pack,Unpack}{4,8} + * + * The struct and pickle (at least) modules need an efficient platform- + * independent way to store floating-point values as byte strings. + * The Pack routines produce a string from a C double, and the Unpack + * routines produce a C double from such a string. The suffix (4 or 8) + * specifies the number of bytes in the string. + * + * On platforms that appear to use (see _PyFloat_Init()) IEEE-754 formats + * these functions work by copying bits. On other platforms, the formats the + * 4- byte format is identical to the IEEE-754 single precision format, and + * the 8-byte format to the IEEE-754 double precision format, although the + * packing of INFs and NaNs (if such things exist on the platform) isn't + * handled correctly, and attempting to unpack a string containing an IEEE + * INF or NaN will raise an exception. + * + * On non-IEEE platforms with more precision, or larger dynamic range, than + * 754 supports, not all values can be packed; on non-IEEE platforms with less + * precision, or smaller dynamic range, not all values can be unpacked. What + * happens in such cases is partly accidental (alas). + */ + +/* The pack routines write 4 or 8 bytes, starting at p. le is a bool + * argument, true if you want the string in little-endian format (exponent + * last, at p+3 or p+7), false if you want big-endian format (exponent + * first, at p). + * Return value: 0 if all is OK, -1 if error (and an exception is + * set, most likely OverflowError). + * There are two problems on non-IEEE platforms: + * 1): What this does is undefined if x is a NaN or infinity. + * 2): -0.0 and +0.0 produce the same string. + */ +PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); +PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); + +/* Needed for the old way for marshal to store a floating point number. + Returns the string length copied into p, -1 on error. + */ +PyAPI_FUNC(int) _PyFloat_Repr(double x, char *p, size_t len); + +/* Used to get the important decimal digits of a double */ +PyAPI_FUNC(int) _PyFloat_Digits(char *buf, double v, int *signum); +PyAPI_FUNC(void) _PyFloat_DigitsInit(void); + +/* The unpack routines read 4 or 8 bytes, starting at p. le is a bool + * argument, true if the string is in little-endian format (exponent + * last, at p+3 or p+7), false if big-endian (exponent first, at p). + * Return value: The unpacked double. On error, this is -1.0 and + * PyErr_Occurred() is true (and an exception is set, most likely + * OverflowError). Note that on a non-IEEE platform this will refuse + * to unpack a string that represents a NaN or infinity. + */ +PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); +PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); + +/* free list api */ +PyAPI_FUNC(int) PyFloat_ClearFreeList(void); + +PyAPI_FUNC(void) _PyFloat_DebugMallocStats(FILE* out); + +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +PyAPI_FUNC(int) _PyFloat_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); +#endif /* Py_LIMITED_API */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FLOATOBJECT_H */ diff --git a/libs/nxpy/include/frameobject.h b/libs/nxpy/include/frameobject.h index 00c50933..14b55c4e 100644 --- a/libs/nxpy/include/frameobject.h +++ b/libs/nxpy/include/frameobject.h @@ -1,95 +1,95 @@ - -/* Frame object interface */ - -#ifndef Py_LIMITED_API -#ifndef Py_FRAMEOBJECT_H -#define Py_FRAMEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int b_type; /* what kind of block this is */ - int b_handler; /* where to jump to find handler */ - int b_level; /* value stack level to pop to */ -} PyTryBlock; - -typedef struct _frame { - PyObject_VAR_HEAD - struct _frame *f_back; /* previous frame, or NULL */ - PyCodeObject *f_code; /* code segment */ - PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ - PyObject *f_globals; /* global symbol table (PyDictObject) */ - PyObject *f_locals; /* local symbol table (any mapping) */ - PyObject **f_valuestack; /* points after the last local */ - /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. - Frame evaluation usually NULLs it, but a frame that yields sets it - to the current stack top. */ - PyObject **f_stacktop; - PyObject *f_trace; /* Trace function */ - - /* In a generator, we need to be able to swap between the exception - state inside the generator and the exception state of the calling - frame (which shouldn't be impacted when the generator "yields" - from an except handler). - These three fields exist exactly for that, and are unused for - non-generator frames. See the save_exc_state and swap_exc_state - functions in ceval.c for details of their use. */ - PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; - /* Borrowed reference to a generator, or NULL */ - PyObject *f_gen; - - int f_lasti; /* Last instruction if called */ - /* Call PyFrame_GetLineNumber() instead of reading this field - directly. As of 2.3 f_lineno is only valid when tracing is - active (i.e. when f_trace is set). At other times we use - PyCode_Addr2Line to calculate the line from the current - bytecode index. */ - int f_lineno; /* Current line number */ - int f_iblock; /* index in f_blockstack */ - char f_executing; /* whether the frame is still executing */ - PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ - PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ -} PyFrameObject; - - -/* Standard object interface */ - -PyAPI_DATA(PyTypeObject) PyFrame_Type; - -#define PyFrame_Check(op) (Py_TYPE(op) == &PyFrame_Type) - -PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, - PyObject *, PyObject *); - - -/* The rest of the interface is specific for frame objects */ - -/* Block management functions */ - -PyAPI_FUNC(void) PyFrame_BlockSetup(PyFrameObject *, int, int, int); -PyAPI_FUNC(PyTryBlock *) PyFrame_BlockPop(PyFrameObject *); - -/* Extend the value stack */ - -PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int); - -/* Conversions between "fast locals" and locals in dictionary */ - -PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); - -PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); -PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); - -PyAPI_FUNC(int) PyFrame_ClearFreeList(void); - -PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out); - -/* Return the line of code the frame is currently executing. */ -PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FRAMEOBJECT_H */ -#endif /* Py_LIMITED_API */ + +/* Frame object interface */ + +#ifndef Py_LIMITED_API +#ifndef Py_FRAMEOBJECT_H +#define Py_FRAMEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int b_type; /* what kind of block this is */ + int b_handler; /* where to jump to find handler */ + int b_level; /* value stack level to pop to */ +} PyTryBlock; + +typedef struct _frame { + PyObject_VAR_HEAD + struct _frame *f_back; /* previous frame, or NULL */ + PyCodeObject *f_code; /* code segment */ + PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ + PyObject *f_globals; /* global symbol table (PyDictObject) */ + PyObject *f_locals; /* local symbol table (any mapping) */ + PyObject **f_valuestack; /* points after the last local */ + /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. + Frame evaluation usually NULLs it, but a frame that yields sets it + to the current stack top. */ + PyObject **f_stacktop; + PyObject *f_trace; /* Trace function */ + + /* In a generator, we need to be able to swap between the exception + state inside the generator and the exception state of the calling + frame (which shouldn't be impacted when the generator "yields" + from an except handler). + These three fields exist exactly for that, and are unused for + non-generator frames. See the save_exc_state and swap_exc_state + functions in ceval.c for details of their use. */ + PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; + /* Borrowed reference to a generator, or NULL */ + PyObject *f_gen; + + int f_lasti; /* Last instruction if called */ + /* Call PyFrame_GetLineNumber() instead of reading this field + directly. As of 2.3 f_lineno is only valid when tracing is + active (i.e. when f_trace is set). At other times we use + PyCode_Addr2Line to calculate the line from the current + bytecode index. */ + int f_lineno; /* Current line number */ + int f_iblock; /* index in f_blockstack */ + char f_executing; /* whether the frame is still executing */ + PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ + PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ +} PyFrameObject; + + +/* Standard object interface */ + +PyAPI_DATA(PyTypeObject) PyFrame_Type; + +#define PyFrame_Check(op) (Py_TYPE(op) == &PyFrame_Type) + +PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, + PyObject *, PyObject *); + + +/* The rest of the interface is specific for frame objects */ + +/* Block management functions */ + +PyAPI_FUNC(void) PyFrame_BlockSetup(PyFrameObject *, int, int, int); +PyAPI_FUNC(PyTryBlock *) PyFrame_BlockPop(PyFrameObject *); + +/* Extend the value stack */ + +PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int); + +/* Conversions between "fast locals" and locals in dictionary */ + +PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); + +PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); +PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); + +PyAPI_FUNC(int) PyFrame_ClearFreeList(void); + +PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out); + +/* Return the line of code the frame is currently executing. */ +PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FRAMEOBJECT_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/funcobject.h b/libs/nxpy/include/funcobject.h index cc1426cd..49f4e898 100644 --- a/libs/nxpy/include/funcobject.h +++ b/libs/nxpy/include/funcobject.h @@ -1,89 +1,89 @@ - -/* Function object interface */ -#ifndef Py_LIMITED_API -#ifndef Py_FUNCOBJECT_H -#define Py_FUNCOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Function objects and code objects should not be confused with each other: - * - * Function objects are created by the execution of the 'def' statement. - * They reference a code object in their __code__ attribute, which is a - * purely syntactic object, i.e. nothing more than a compiled version of some - * source code lines. There is one code object per source code "fragment", - * but each code object can be referenced by zero or many function objects - * depending only on how many times the 'def' statement in the source was - * executed so far. - */ - -typedef struct { - PyObject_HEAD - PyObject *func_code; /* A code object, the __code__ attribute */ - PyObject *func_globals; /* A dictionary (other mappings won't do) */ - PyObject *func_defaults; /* NULL or a tuple */ - PyObject *func_kwdefaults; /* NULL or a dict */ - PyObject *func_closure; /* NULL or a tuple of cell objects */ - PyObject *func_doc; /* The __doc__ attribute, can be anything */ - PyObject *func_name; /* The __name__ attribute, a string object */ - PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */ - PyObject *func_weakreflist; /* List of weak references */ - PyObject *func_module; /* The __module__ attribute, can be anything */ - PyObject *func_annotations; /* Annotations, a dict or NULL */ - PyObject *func_qualname; /* The qualified name */ - - /* Invariant: - * func_closure contains the bindings for func_code->co_freevars, so - * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) - * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). - */ -} PyFunctionObject; - -PyAPI_DATA(PyTypeObject) PyFunction_Type; - -#define PyFunction_Check(op) (Py_TYPE(op) == &PyFunction_Type) - -PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *); -PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetKwDefaults(PyObject *); -PyAPI_FUNC(int) PyFunction_SetKwDefaults(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *); -PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); -PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#define PyFunction_GET_CODE(func) \ - (((PyFunctionObject *)func) -> func_code) -#define PyFunction_GET_GLOBALS(func) \ - (((PyFunctionObject *)func) -> func_globals) -#define PyFunction_GET_MODULE(func) \ - (((PyFunctionObject *)func) -> func_module) -#define PyFunction_GET_DEFAULTS(func) \ - (((PyFunctionObject *)func) -> func_defaults) -#define PyFunction_GET_KW_DEFAULTS(func) \ - (((PyFunctionObject *)func) -> func_kwdefaults) -#define PyFunction_GET_CLOSURE(func) \ - (((PyFunctionObject *)func) -> func_closure) -#define PyFunction_GET_ANNOTATIONS(func) \ - (((PyFunctionObject *)func) -> func_annotations) - -/* The classmethod and staticmethod types lives here, too */ -PyAPI_DATA(PyTypeObject) PyClassMethod_Type; -PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; - -PyAPI_FUNC(PyObject *) PyClassMethod_New(PyObject *); -PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_FUNCOBJECT_H */ -#endif /* Py_LIMITED_API */ + +/* Function object interface */ +#ifndef Py_LIMITED_API +#ifndef Py_FUNCOBJECT_H +#define Py_FUNCOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Function objects and code objects should not be confused with each other: + * + * Function objects are created by the execution of the 'def' statement. + * They reference a code object in their __code__ attribute, which is a + * purely syntactic object, i.e. nothing more than a compiled version of some + * source code lines. There is one code object per source code "fragment", + * but each code object can be referenced by zero or many function objects + * depending only on how many times the 'def' statement in the source was + * executed so far. + */ + +typedef struct { + PyObject_HEAD + PyObject *func_code; /* A code object, the __code__ attribute */ + PyObject *func_globals; /* A dictionary (other mappings won't do) */ + PyObject *func_defaults; /* NULL or a tuple */ + PyObject *func_kwdefaults; /* NULL or a dict */ + PyObject *func_closure; /* NULL or a tuple of cell objects */ + PyObject *func_doc; /* The __doc__ attribute, can be anything */ + PyObject *func_name; /* The __name__ attribute, a string object */ + PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */ + PyObject *func_weakreflist; /* List of weak references */ + PyObject *func_module; /* The __module__ attribute, can be anything */ + PyObject *func_annotations; /* Annotations, a dict or NULL */ + PyObject *func_qualname; /* The qualified name */ + + /* Invariant: + * func_closure contains the bindings for func_code->co_freevars, so + * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) + * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). + */ +} PyFunctionObject; + +PyAPI_DATA(PyTypeObject) PyFunction_Type; + +#define PyFunction_Check(op) (Py_TYPE(op) == &PyFunction_Type) + +PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *); +PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetKwDefaults(PyObject *); +PyAPI_FUNC(int) PyFunction_SetKwDefaults(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *); +PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); +PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyFunction_GET_CODE(func) \ + (((PyFunctionObject *)func) -> func_code) +#define PyFunction_GET_GLOBALS(func) \ + (((PyFunctionObject *)func) -> func_globals) +#define PyFunction_GET_MODULE(func) \ + (((PyFunctionObject *)func) -> func_module) +#define PyFunction_GET_DEFAULTS(func) \ + (((PyFunctionObject *)func) -> func_defaults) +#define PyFunction_GET_KW_DEFAULTS(func) \ + (((PyFunctionObject *)func) -> func_kwdefaults) +#define PyFunction_GET_CLOSURE(func) \ + (((PyFunctionObject *)func) -> func_closure) +#define PyFunction_GET_ANNOTATIONS(func) \ + (((PyFunctionObject *)func) -> func_annotations) + +/* The classmethod and staticmethod types lives here, too */ +PyAPI_DATA(PyTypeObject) PyClassMethod_Type; +PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; + +PyAPI_FUNC(PyObject *) PyClassMethod_New(PyObject *); +PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FUNCOBJECT_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/genobject.h b/libs/nxpy/include/genobject.h index 61e708a7..f3e1ee5b 100644 --- a/libs/nxpy/include/genobject.h +++ b/libs/nxpy/include/genobject.h @@ -1,73 +1,73 @@ - -/* Generator object interface */ - -#ifndef Py_LIMITED_API -#ifndef Py_GENOBJECT_H -#define Py_GENOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -struct _frame; /* Avoid including frameobject.h */ - -/* _PyGenObject_HEAD defines the initial segment of generator - and coroutine objects. */ -#define _PyGenObject_HEAD(prefix) \ - PyObject_HEAD \ - /* Note: gi_frame can be NULL if the generator is "finished" */ \ - struct _frame *prefix##_frame; \ - /* True if generator is being executed. */ \ - char prefix##_running; \ - /* The code object backing the generator */ \ - PyObject *prefix##_code; \ - /* List of weak reference. */ \ - PyObject *prefix##_weakreflist; \ - /* Name of the generator. */ \ - PyObject *prefix##_name; \ - /* Qualified name of the generator. */ \ - PyObject *prefix##_qualname; - -typedef struct { - /* The gi_ prefix is intended to remind of generator-iterator. */ - _PyGenObject_HEAD(gi) -} PyGenObject; - -PyAPI_DATA(PyTypeObject) PyGen_Type; - -#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type) -#define PyGen_CheckExact(op) (Py_TYPE(op) == &PyGen_Type) - -PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); -PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *, - PyObject *name, PyObject *qualname); -PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); -PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); -PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); -PyObject *_PyGen_Send(PyGenObject *, PyObject *); -PyObject *_PyGen_yf(PyGenObject *); -PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); - -#ifndef Py_LIMITED_API -typedef struct { - _PyGenObject_HEAD(cr) -} PyCoroObject; - -PyAPI_DATA(PyTypeObject) PyCoro_Type; -PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type; - -PyAPI_DATA(PyTypeObject) _PyAIterWrapper_Type; -PyObject *_PyAIterWrapper_New(PyObject *aiter); - -#define PyCoro_CheckExact(op) (Py_TYPE(op) == &PyCoro_Type) -PyObject *_PyCoro_GetAwaitableIter(PyObject *o); -PyAPI_FUNC(PyObject *) PyCoro_New(struct _frame *, - PyObject *name, PyObject *qualname); -#endif - -#undef _PyGenObject_HEAD - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GENOBJECT_H */ -#endif /* Py_LIMITED_API */ + +/* Generator object interface */ + +#ifndef Py_LIMITED_API +#ifndef Py_GENOBJECT_H +#define Py_GENOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct _frame; /* Avoid including frameobject.h */ + +/* _PyGenObject_HEAD defines the initial segment of generator + and coroutine objects. */ +#define _PyGenObject_HEAD(prefix) \ + PyObject_HEAD \ + /* Note: gi_frame can be NULL if the generator is "finished" */ \ + struct _frame *prefix##_frame; \ + /* True if generator is being executed. */ \ + char prefix##_running; \ + /* The code object backing the generator */ \ + PyObject *prefix##_code; \ + /* List of weak reference. */ \ + PyObject *prefix##_weakreflist; \ + /* Name of the generator. */ \ + PyObject *prefix##_name; \ + /* Qualified name of the generator. */ \ + PyObject *prefix##_qualname; + +typedef struct { + /* The gi_ prefix is intended to remind of generator-iterator. */ + _PyGenObject_HEAD(gi) +} PyGenObject; + +PyAPI_DATA(PyTypeObject) PyGen_Type; + +#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type) +#define PyGen_CheckExact(op) (Py_TYPE(op) == &PyGen_Type) + +PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); +PyAPI_FUNC(PyObject *) PyGen_NewWithQualName(struct _frame *, + PyObject *name, PyObject *qualname); +PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); +PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *); +PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); +PyObject *_PyGen_Send(PyGenObject *, PyObject *); +PyObject *_PyGen_yf(PyGenObject *); +PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); + +#ifndef Py_LIMITED_API +typedef struct { + _PyGenObject_HEAD(cr) +} PyCoroObject; + +PyAPI_DATA(PyTypeObject) PyCoro_Type; +PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type; + +PyAPI_DATA(PyTypeObject) _PyAIterWrapper_Type; +PyObject *_PyAIterWrapper_New(PyObject *aiter); + +#define PyCoro_CheckExact(op) (Py_TYPE(op) == &PyCoro_Type) +PyObject *_PyCoro_GetAwaitableIter(PyObject *o); +PyAPI_FUNC(PyObject *) PyCoro_New(struct _frame *, + PyObject *name, PyObject *qualname); +#endif + +#undef _PyGenObject_HEAD + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GENOBJECT_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/graminit.h b/libs/nxpy/include/graminit.h index d030bc3d..5dedde19 100644 --- a/libs/nxpy/include/graminit.h +++ b/libs/nxpy/include/graminit.h @@ -1,87 +1,87 @@ -/* Generated by Parser/pgen */ - -#define single_input 256 -#define file_input 257 -#define eval_input 258 -#define decorator 259 -#define decorators 260 -#define decorated 261 -#define async_funcdef 262 -#define funcdef 263 -#define parameters 264 -#define typedargslist 265 -#define tfpdef 266 -#define varargslist 267 -#define vfpdef 268 -#define stmt 269 -#define simple_stmt 270 -#define small_stmt 271 -#define expr_stmt 272 -#define testlist_star_expr 273 -#define augassign 274 -#define del_stmt 275 -#define pass_stmt 276 -#define flow_stmt 277 -#define break_stmt 278 -#define continue_stmt 279 -#define return_stmt 280 -#define yield_stmt 281 -#define raise_stmt 282 -#define import_stmt 283 -#define import_name 284 -#define import_from 285 -#define import_as_name 286 -#define dotted_as_name 287 -#define import_as_names 288 -#define dotted_as_names 289 -#define dotted_name 290 -#define global_stmt 291 -#define nonlocal_stmt 292 -#define assert_stmt 293 -#define compound_stmt 294 -#define async_stmt 295 -#define if_stmt 296 -#define while_stmt 297 -#define for_stmt 298 -#define try_stmt 299 -#define with_stmt 300 -#define with_item 301 -#define except_clause 302 -#define suite 303 -#define test 304 -#define test_nocond 305 -#define lambdef 306 -#define lambdef_nocond 307 -#define or_test 308 -#define and_test 309 -#define not_test 310 -#define comparison 311 -#define comp_op 312 -#define star_expr 313 -#define expr 314 -#define xor_expr 315 -#define and_expr 316 -#define shift_expr 317 -#define arith_expr 318 -#define term 319 -#define factor 320 -#define power 321 -#define atom_expr 322 -#define atom 323 -#define testlist_comp 324 -#define trailer 325 -#define subscriptlist 326 -#define subscript 327 -#define sliceop 328 -#define exprlist 329 -#define testlist 330 -#define dictorsetmaker 331 -#define classdef 332 -#define arglist 333 -#define argument 334 -#define comp_iter 335 -#define comp_for 336 -#define comp_if 337 -#define encoding_decl 338 -#define yield_expr 339 -#define yield_arg 340 +/* Generated by Parser/pgen */ + +#define single_input 256 +#define file_input 257 +#define eval_input 258 +#define decorator 259 +#define decorators 260 +#define decorated 261 +#define async_funcdef 262 +#define funcdef 263 +#define parameters 264 +#define typedargslist 265 +#define tfpdef 266 +#define varargslist 267 +#define vfpdef 268 +#define stmt 269 +#define simple_stmt 270 +#define small_stmt 271 +#define expr_stmt 272 +#define testlist_star_expr 273 +#define augassign 274 +#define del_stmt 275 +#define pass_stmt 276 +#define flow_stmt 277 +#define break_stmt 278 +#define continue_stmt 279 +#define return_stmt 280 +#define yield_stmt 281 +#define raise_stmt 282 +#define import_stmt 283 +#define import_name 284 +#define import_from 285 +#define import_as_name 286 +#define dotted_as_name 287 +#define import_as_names 288 +#define dotted_as_names 289 +#define dotted_name 290 +#define global_stmt 291 +#define nonlocal_stmt 292 +#define assert_stmt 293 +#define compound_stmt 294 +#define async_stmt 295 +#define if_stmt 296 +#define while_stmt 297 +#define for_stmt 298 +#define try_stmt 299 +#define with_stmt 300 +#define with_item 301 +#define except_clause 302 +#define suite 303 +#define test 304 +#define test_nocond 305 +#define lambdef 306 +#define lambdef_nocond 307 +#define or_test 308 +#define and_test 309 +#define not_test 310 +#define comparison 311 +#define comp_op 312 +#define star_expr 313 +#define expr 314 +#define xor_expr 315 +#define and_expr 316 +#define shift_expr 317 +#define arith_expr 318 +#define term 319 +#define factor 320 +#define power 321 +#define atom_expr 322 +#define atom 323 +#define testlist_comp 324 +#define trailer 325 +#define subscriptlist 326 +#define subscript 327 +#define sliceop 328 +#define exprlist 329 +#define testlist 330 +#define dictorsetmaker 331 +#define classdef 332 +#define arglist 333 +#define argument 334 +#define comp_iter 335 +#define comp_for 336 +#define comp_if 337 +#define encoding_decl 338 +#define yield_expr 339 +#define yield_arg 340 diff --git a/libs/nxpy/include/grammar.h b/libs/nxpy/include/grammar.h index 85120b9b..e48993f0 100644 --- a/libs/nxpy/include/grammar.h +++ b/libs/nxpy/include/grammar.h @@ -1,93 +1,93 @@ - -/* Grammar interface */ - -#ifndef Py_GRAMMAR_H -#define Py_GRAMMAR_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "bitset.h" /* Sigh... */ - -/* A label of an arc */ - -typedef struct { - int lb_type; - char *lb_str; -} label; - -#define EMPTY 0 /* Label number 0 is by definition the empty label */ - -/* A list of labels */ - -typedef struct { - int ll_nlabels; - label *ll_label; -} labellist; - -/* An arc from one state to another */ - -typedef struct { - short a_lbl; /* Label of this arc */ - short a_arrow; /* State where this arc goes to */ -} arc; - -/* A state in a DFA */ - -typedef struct { - int s_narcs; - arc *s_arc; /* Array of arcs */ - - /* Optional accelerators */ - int s_lower; /* Lowest label index */ - int s_upper; /* Highest label index */ - int *s_accel; /* Accelerator */ - int s_accept; /* Nonzero for accepting state */ -} state; - -/* A DFA */ - -typedef struct { - int d_type; /* Non-terminal this represents */ - char *d_name; /* For printing */ - int d_initial; /* Initial state */ - int d_nstates; - state *d_state; /* Array of states */ - bitset d_first; -} dfa; - -/* A grammar */ - -typedef struct { - int g_ndfas; - dfa *g_dfa; /* Array of DFAs */ - labellist g_ll; - int g_start; /* Start symbol of the grammar */ - int g_accel; /* Set if accelerators present */ -} grammar; - -/* FUNCTIONS */ - -grammar *newgrammar(int start); -dfa *adddfa(grammar *g, int type, const char *name); -int addstate(dfa *d); -void addarc(dfa *d, int from, int to, int lbl); -dfa *PyGrammar_FindDFA(grammar *g, int type); - -int addlabel(labellist *ll, int type, const char *str); -int findlabel(labellist *ll, int type, const char *str); -const char *PyGrammar_LabelRepr(label *lb); -void translatelabels(grammar *g); - -void addfirstsets(grammar *g); - -void PyGrammar_AddAccelerators(grammar *g); -void PyGrammar_RemoveAccelerators(grammar *); - -void printgrammar(grammar *g, FILE *fp); -void printnonterminals(grammar *g, FILE *fp); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GRAMMAR_H */ + +/* Grammar interface */ + +#ifndef Py_GRAMMAR_H +#define Py_GRAMMAR_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "bitset.h" /* Sigh... */ + +/* A label of an arc */ + +typedef struct { + int lb_type; + char *lb_str; +} label; + +#define EMPTY 0 /* Label number 0 is by definition the empty label */ + +/* A list of labels */ + +typedef struct { + int ll_nlabels; + label *ll_label; +} labellist; + +/* An arc from one state to another */ + +typedef struct { + short a_lbl; /* Label of this arc */ + short a_arrow; /* State where this arc goes to */ +} arc; + +/* A state in a DFA */ + +typedef struct { + int s_narcs; + arc *s_arc; /* Array of arcs */ + + /* Optional accelerators */ + int s_lower; /* Lowest label index */ + int s_upper; /* Highest label index */ + int *s_accel; /* Accelerator */ + int s_accept; /* Nonzero for accepting state */ +} state; + +/* A DFA */ + +typedef struct { + int d_type; /* Non-terminal this represents */ + char *d_name; /* For printing */ + int d_initial; /* Initial state */ + int d_nstates; + state *d_state; /* Array of states */ + bitset d_first; +} dfa; + +/* A grammar */ + +typedef struct { + int g_ndfas; + dfa *g_dfa; /* Array of DFAs */ + labellist g_ll; + int g_start; /* Start symbol of the grammar */ + int g_accel; /* Set if accelerators present */ +} grammar; + +/* FUNCTIONS */ + +grammar *newgrammar(int start); +dfa *adddfa(grammar *g, int type, const char *name); +int addstate(dfa *d); +void addarc(dfa *d, int from, int to, int lbl); +dfa *PyGrammar_FindDFA(grammar *g, int type); + +int addlabel(labellist *ll, int type, const char *str); +int findlabel(labellist *ll, int type, const char *str); +const char *PyGrammar_LabelRepr(label *lb); +void translatelabels(grammar *g); + +void addfirstsets(grammar *g); + +void PyGrammar_AddAccelerators(grammar *g); +void PyGrammar_RemoveAccelerators(grammar *); + +void printgrammar(grammar *g, FILE *fp); +void printnonterminals(grammar *g, FILE *fp); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GRAMMAR_H */ diff --git a/libs/nxpy/include/import.h b/libs/nxpy/include/import.h index afdfac2a..50f74045 100644 --- a/libs/nxpy/include/import.h +++ b/libs/nxpy/include/import.h @@ -1,130 +1,130 @@ - -/* Module definition and import interface */ - -#ifndef Py_IMPORT_H -#define Py_IMPORT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(void) _PyImportZip_Init(void); - -PyMODINIT_FUNC PyInit_imp(void); -PyAPI_FUNC(long) PyImport_GetMagicNumber(void); -PyAPI_FUNC(const char *) PyImport_GetMagicTag(void); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModule( - const char *name, /* UTF-8 encoded string */ - PyObject *co - ); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx( - const char *name, /* UTF-8 encoded string */ - PyObject *co, - const char *pathname /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleWithPathnames( - const char *name, /* UTF-8 encoded string */ - PyObject *co, - const char *pathname, /* decoded from the filesystem encoding */ - const char *cpathname /* decoded from the filesystem encoding */ - ); -PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject( - PyObject *name, - PyObject *co, - PyObject *pathname, - PyObject *cpathname - ); -PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void); -PyAPI_FUNC(PyObject *) PyImport_AddModuleObject( - PyObject *name - ); -PyAPI_FUNC(PyObject *) PyImport_AddModule( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModule( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel( - const char *name, /* UTF-8 encoded string */ - PyObject *globals, - PyObject *locals, - PyObject *fromlist, - int level - ); -PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevelObject( - PyObject *name, - PyObject *globals, - PyObject *locals, - PyObject *fromlist, - int level - ); - -#define PyImport_ImportModuleEx(n, g, l, f) \ - PyImport_ImportModuleLevel(n, g, l, f, 0) - -PyAPI_FUNC(PyObject *) PyImport_GetImporter(PyObject *path); -PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name); -PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m); -PyAPI_FUNC(void) PyImport_Cleanup(void); -PyAPI_FUNC(int) PyImport_ImportFrozenModuleObject( - PyObject *name - ); -PyAPI_FUNC(int) PyImport_ImportFrozenModule( - const char *name /* UTF-8 encoded string */ - ); - -#ifndef Py_LIMITED_API -#ifdef WITH_THREAD -PyAPI_FUNC(void) _PyImport_AcquireLock(void); -PyAPI_FUNC(int) _PyImport_ReleaseLock(void); -#else -#define _PyImport_AcquireLock() -#define _PyImport_ReleaseLock() 1 -#endif - -PyAPI_FUNC(void) _PyImport_ReInitLock(void); - -PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *); -PyAPI_FUNC(int) _PyImport_FixupBuiltin( - PyObject *mod, - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *, PyObject *); - -struct _inittab { - const char *name; /* ASCII encoded string */ - PyObject* (*initfunc)(void); -}; -PyAPI_DATA(struct _inittab *) PyImport_Inittab; -PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); -#endif /* Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PyNullImporter_Type; - -PyAPI_FUNC(int) PyImport_AppendInittab( - const char *name, /* ASCII encoded string */ - PyObject* (*initfunc)(void) - ); - -#ifndef Py_LIMITED_API -struct _frozen { - const char *name; /* ASCII encoded string */ - const unsigned char *code; - int size; -}; - -/* Embedding apps may change this pointer to point to their favorite - collection of frozen modules: */ - -PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_IMPORT_H */ + +/* Module definition and import interface */ + +#ifndef Py_IMPORT_H +#define Py_IMPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(void) _PyImportZip_Init(void); + +PyMODINIT_FUNC PyInit_imp(void); +PyAPI_FUNC(long) PyImport_GetMagicNumber(void); +PyAPI_FUNC(const char *) PyImport_GetMagicTag(void); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModule( + const char *name, /* UTF-8 encoded string */ + PyObject *co + ); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx( + const char *name, /* UTF-8 encoded string */ + PyObject *co, + const char *pathname /* decoded from the filesystem encoding */ + ); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleWithPathnames( + const char *name, /* UTF-8 encoded string */ + PyObject *co, + const char *pathname, /* decoded from the filesystem encoding */ + const char *cpathname /* decoded from the filesystem encoding */ + ); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject( + PyObject *name, + PyObject *co, + PyObject *pathname, + PyObject *cpathname + ); +PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void); +PyAPI_FUNC(PyObject *) PyImport_AddModuleObject( + PyObject *name + ); +PyAPI_FUNC(PyObject *) PyImport_AddModule( + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) PyImport_ImportModule( + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock( + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel( + const char *name, /* UTF-8 encoded string */ + PyObject *globals, + PyObject *locals, + PyObject *fromlist, + int level + ); +PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevelObject( + PyObject *name, + PyObject *globals, + PyObject *locals, + PyObject *fromlist, + int level + ); + +#define PyImport_ImportModuleEx(n, g, l, f) \ + PyImport_ImportModuleLevel(n, g, l, f, 0) + +PyAPI_FUNC(PyObject *) PyImport_GetImporter(PyObject *path); +PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name); +PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m); +PyAPI_FUNC(void) PyImport_Cleanup(void); +PyAPI_FUNC(int) PyImport_ImportFrozenModuleObject( + PyObject *name + ); +PyAPI_FUNC(int) PyImport_ImportFrozenModule( + const char *name /* UTF-8 encoded string */ + ); + +#ifndef Py_LIMITED_API +#ifdef WITH_THREAD +PyAPI_FUNC(void) _PyImport_AcquireLock(void); +PyAPI_FUNC(int) _PyImport_ReleaseLock(void); +#else +#define _PyImport_AcquireLock() +#define _PyImport_ReleaseLock() 1 +#endif + +PyAPI_FUNC(void) _PyImport_ReInitLock(void); + +PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin( + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *); +PyAPI_FUNC(int) _PyImport_FixupBuiltin( + PyObject *mod, + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *, PyObject *); + +struct _inittab { + const char *name; /* ASCII encoded string */ + PyObject* (*initfunc)(void); +}; +PyAPI_DATA(struct _inittab *) PyImport_Inittab; +PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); +#endif /* Py_LIMITED_API */ + +PyAPI_DATA(PyTypeObject) PyNullImporter_Type; + +PyAPI_FUNC(int) PyImport_AppendInittab( + const char *name, /* ASCII encoded string */ + PyObject* (*initfunc)(void) + ); + +#ifndef Py_LIMITED_API +struct _frozen { + const char *name; /* ASCII encoded string */ + const unsigned char *code; + int size; +}; + +/* Embedding apps may change this pointer to point to their favorite + collection of frozen modules: */ + +PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_IMPORT_H */ diff --git a/libs/nxpy/include/intrcheck.h b/libs/nxpy/include/intrcheck.h index f53fee1a..51e50ade 100644 --- a/libs/nxpy/include/intrcheck.h +++ b/libs/nxpy/include/intrcheck.h @@ -1,21 +1,21 @@ - -#ifndef Py_INTRCHECK_H -#define Py_INTRCHECK_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(int) PyOS_InterruptOccurred(void); -PyAPI_FUNC(void) PyOS_InitInterrupts(void); -PyAPI_FUNC(void) PyOS_AfterFork(void); -PyAPI_FUNC(int) _PyOS_IsMainThread(void); - -#ifdef MS_WINDOWS -/* windows.h is not included by Python.h so use void* instead of HANDLE */ -PyAPI_FUNC(void*) _PyOS_SigintEvent(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_INTRCHECK_H */ + +#ifndef Py_INTRCHECK_H +#define Py_INTRCHECK_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(int) PyOS_InterruptOccurred(void); +PyAPI_FUNC(void) PyOS_InitInterrupts(void); +PyAPI_FUNC(void) PyOS_AfterFork(void); +PyAPI_FUNC(int) _PyOS_IsMainThread(void); + +#ifdef MS_WINDOWS +/* windows.h is not included by Python.h so use void* instead of HANDLE */ +PyAPI_FUNC(void*) _PyOS_SigintEvent(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTRCHECK_H */ diff --git a/libs/nxpy/include/iterobject.h b/libs/nxpy/include/iterobject.h index f61726f1..610362ad 100644 --- a/libs/nxpy/include/iterobject.h +++ b/libs/nxpy/include/iterobject.h @@ -1,25 +1,25 @@ -#ifndef Py_ITEROBJECT_H -#define Py_ITEROBJECT_H -/* Iterators (the basic kind, over a sequence) */ -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PySeqIter_Type; -PyAPI_DATA(PyTypeObject) PyCallIter_Type; -PyAPI_DATA(PyTypeObject) PyCmpWrapper_Type; - -#define PySeqIter_Check(op) (Py_TYPE(op) == &PySeqIter_Type) - -PyAPI_FUNC(PyObject *) PySeqIter_New(PyObject *); - - -#define PyCallIter_Check(op) (Py_TYPE(op) == &PyCallIter_Type) - -PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ITEROBJECT_H */ - +#ifndef Py_ITEROBJECT_H +#define Py_ITEROBJECT_H +/* Iterators (the basic kind, over a sequence) */ +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PySeqIter_Type; +PyAPI_DATA(PyTypeObject) PyCallIter_Type; +PyAPI_DATA(PyTypeObject) PyCmpWrapper_Type; + +#define PySeqIter_Check(op) (Py_TYPE(op) == &PySeqIter_Type) + +PyAPI_FUNC(PyObject *) PySeqIter_New(PyObject *); + + +#define PyCallIter_Check(op) (Py_TYPE(op) == &PyCallIter_Type) + +PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ITEROBJECT_H */ + diff --git a/libs/nxpy/include/listobject.h b/libs/nxpy/include/listobject.h index 31843b5d..1f3efe7c 100644 --- a/libs/nxpy/include/listobject.h +++ b/libs/nxpy/include/listobject.h @@ -1,81 +1,81 @@ - -/* List object interface */ - -/* -Another generally useful object type is a list of object pointers. -This is a mutable type: the list items can be changed, and items can be -added or removed. Out-of-range indices or non-list objects are ignored. - -*** WARNING *** PyList_SetItem does not increment the new item's reference -count, but does decrement the reference count of the item it replaces, -if not nil. It does *decrement* the reference count if it is *not* -inserted in the list. Similarly, PyList_GetItem does not increment the -returned item's reference count. -*/ - -#ifndef Py_LISTOBJECT_H -#define Py_LISTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_VAR_HEAD - /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */ - PyObject **ob_item; - - /* ob_item contains space for 'allocated' elements. The number - * currently in use is ob_size. - * Invariants: - * 0 <= ob_size <= allocated - * len(list) == ob_size - * ob_item == NULL implies ob_size == allocated == 0 - * list.sort() temporarily sets allocated to -1 to detect mutations. - * - * Items must normally not be NULL, except during construction when - * the list is not yet visible outside the function that builds it. - */ - Py_ssize_t allocated; -} PyListObject; -#endif - -PyAPI_DATA(PyTypeObject) PyList_Type; -PyAPI_DATA(PyTypeObject) PyListIter_Type; -PyAPI_DATA(PyTypeObject) PyListRevIter_Type; -PyAPI_DATA(PyTypeObject) PySortWrapper_Type; - -#define PyList_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS) -#define PyList_CheckExact(op) (Py_TYPE(op) == &PyList_Type) - -PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); -PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *); -PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyList_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); -PyAPI_FUNC(int) PyList_SetSlice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); -PyAPI_FUNC(int) PyList_Sort(PyObject *); -PyAPI_FUNC(int) PyList_Reverse(PyObject *); -PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *); - -PyAPI_FUNC(int) PyList_ClearFreeList(void); -PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out); -#endif - -/* Macro, trading safety for speed */ -#ifndef Py_LIMITED_API -#define PyList_GET_ITEM(op, i) (((PyListObject *)(op))->ob_item[i]) -#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v)) -#define PyList_GET_SIZE(op) Py_SIZE(op) -#define _PyList_ITEMS(op) (((PyListObject *)(op))->ob_item) -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LISTOBJECT_H */ + +/* List object interface */ + +/* +Another generally useful object type is a list of object pointers. +This is a mutable type: the list items can be changed, and items can be +added or removed. Out-of-range indices or non-list objects are ignored. + +*** WARNING *** PyList_SetItem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the list. Similarly, PyList_GetItem does not increment the +returned item's reference count. +*/ + +#ifndef Py_LISTOBJECT_H +#define Py_LISTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +typedef struct { + PyObject_VAR_HEAD + /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */ + PyObject **ob_item; + + /* ob_item contains space for 'allocated' elements. The number + * currently in use is ob_size. + * Invariants: + * 0 <= ob_size <= allocated + * len(list) == ob_size + * ob_item == NULL implies ob_size == allocated == 0 + * list.sort() temporarily sets allocated to -1 to detect mutations. + * + * Items must normally not be NULL, except during construction when + * the list is not yet visible outside the function that builds it. + */ + Py_ssize_t allocated; +} PyListObject; +#endif + +PyAPI_DATA(PyTypeObject) PyList_Type; +PyAPI_DATA(PyTypeObject) PyListIter_Type; +PyAPI_DATA(PyTypeObject) PyListRevIter_Type; +PyAPI_DATA(PyTypeObject) PySortWrapper_Type; + +#define PyList_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS) +#define PyList_CheckExact(op) (Py_TYPE(op) == &PyList_Type) + +PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); +PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *); +PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyList_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); +PyAPI_FUNC(int) PyList_SetSlice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Sort(PyObject *); +PyAPI_FUNC(int) PyList_Reverse(PyObject *); +PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *); + +PyAPI_FUNC(int) PyList_ClearFreeList(void); +PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out); +#endif + +/* Macro, trading safety for speed */ +#ifndef Py_LIMITED_API +#define PyList_GET_ITEM(op, i) (((PyListObject *)(op))->ob_item[i]) +#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v)) +#define PyList_GET_SIZE(op) Py_SIZE(op) +#define _PyList_ITEMS(op) (((PyListObject *)(op))->ob_item) +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LISTOBJECT_H */ diff --git a/libs/nxpy/include/longintrepr.h b/libs/nxpy/include/longintrepr.h index bbba4d8d..4ee7d657 100644 --- a/libs/nxpy/include/longintrepr.h +++ b/libs/nxpy/include/longintrepr.h @@ -1,103 +1,103 @@ -#ifndef Py_LIMITED_API -#ifndef Py_LONGINTREPR_H -#define Py_LONGINTREPR_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ - -/* Parameters of the integer representation. There are two different - sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit - integer type, and one set for 15-bit digits with each digit stored in an - unsigned short. The value of PYLONG_BITS_IN_DIGIT, defined either at - configure time or in pyport.h, is used to decide which digit size to use. - - Type 'digit' should be able to hold 2*PyLong_BASE-1, and type 'twodigits' - should be an unsigned integer type able to hold all integers up to - PyLong_BASE*PyLong_BASE-1. x_sub assumes that 'digit' is an unsigned type, - and that overflow is handled by taking the result modulo 2**N for some N > - PyLong_SHIFT. The majority of the code doesn't care about the precise - value of PyLong_SHIFT, but there are some notable exceptions: - - - long_pow() requires that PyLong_SHIFT be divisible by 5 - - - PyLong_{As,From}ByteArray require that PyLong_SHIFT be at least 8 - - - long_hash() requires that PyLong_SHIFT is *strictly* less than the number - of bits in an unsigned long, as do the PyLong <-> long (or unsigned long) - conversion functions - - - the Python int <-> size_t/Py_ssize_t conversion functions expect that - PyLong_SHIFT is strictly less than the number of bits in a size_t - - - the marshal code currently expects that PyLong_SHIFT is a multiple of 15 - - - NSMALLNEGINTS and NSMALLPOSINTS should be small enough to fit in a single - digit; with the current values this forces PyLong_SHIFT >= 9 - - The values 15 and 30 should fit all of the above requirements, on any - platform. -*/ - -#if PYLONG_BITS_IN_DIGIT == 30 -#if !(defined HAVE_UINT64_T && defined HAVE_UINT32_T && \ - defined HAVE_INT64_T && defined HAVE_INT32_T) -#error "30-bit long digits requested, but the necessary types are not available on this platform" -#endif -typedef PY_UINT32_T digit; -typedef PY_INT32_T sdigit; /* signed variant of digit */ -typedef PY_UINT64_T twodigits; -typedef PY_INT64_T stwodigits; /* signed variant of twodigits */ -#define PyLong_SHIFT 30 -#define _PyLong_DECIMAL_SHIFT 9 /* max(e such that 10**e fits in a digit) */ -#define _PyLong_DECIMAL_BASE ((digit)1000000000) /* 10 ** DECIMAL_SHIFT */ -#elif PYLONG_BITS_IN_DIGIT == 15 -typedef unsigned short digit; -typedef short sdigit; /* signed variant of digit */ -typedef unsigned long twodigits; -typedef long stwodigits; /* signed variant of twodigits */ -#define PyLong_SHIFT 15 -#define _PyLong_DECIMAL_SHIFT 4 /* max(e such that 10**e fits in a digit) */ -#define _PyLong_DECIMAL_BASE ((digit)10000) /* 10 ** DECIMAL_SHIFT */ -#else -#error "PYLONG_BITS_IN_DIGIT should be 15 or 30" -#endif -#define PyLong_BASE ((digit)1 << PyLong_SHIFT) -#define PyLong_MASK ((digit)(PyLong_BASE - 1)) - -#if PyLong_SHIFT % 5 != 0 -#error "longobject.c requires that PyLong_SHIFT be divisible by 5" -#endif - -/* Long integer representation. - The absolute value of a number is equal to - SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) - Negative numbers are represented with ob_size < 0; - zero is represented by ob_size == 0. - In a normalized number, ob_digit[abs(ob_size)-1] (the most significant - digit) is never zero. Also, in all cases, for all valid i, - 0 <= ob_digit[i] <= MASK. - The allocation function takes care of allocating extra memory - so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available. - - CAUTION: Generic code manipulating subtypes of PyVarObject has to - aware that ints abuse ob_size's sign bit. -*/ - -struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; -}; - -PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); - -/* Return a copy of src. */ -PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LONGINTREPR_H */ -#endif /* Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_LONGINTREPR_H +#define Py_LONGINTREPR_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ + +/* Parameters of the integer representation. There are two different + sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit + integer type, and one set for 15-bit digits with each digit stored in an + unsigned short. The value of PYLONG_BITS_IN_DIGIT, defined either at + configure time or in pyport.h, is used to decide which digit size to use. + + Type 'digit' should be able to hold 2*PyLong_BASE-1, and type 'twodigits' + should be an unsigned integer type able to hold all integers up to + PyLong_BASE*PyLong_BASE-1. x_sub assumes that 'digit' is an unsigned type, + and that overflow is handled by taking the result modulo 2**N for some N > + PyLong_SHIFT. The majority of the code doesn't care about the precise + value of PyLong_SHIFT, but there are some notable exceptions: + + - long_pow() requires that PyLong_SHIFT be divisible by 5 + + - PyLong_{As,From}ByteArray require that PyLong_SHIFT be at least 8 + + - long_hash() requires that PyLong_SHIFT is *strictly* less than the number + of bits in an unsigned long, as do the PyLong <-> long (or unsigned long) + conversion functions + + - the Python int <-> size_t/Py_ssize_t conversion functions expect that + PyLong_SHIFT is strictly less than the number of bits in a size_t + + - the marshal code currently expects that PyLong_SHIFT is a multiple of 15 + + - NSMALLNEGINTS and NSMALLPOSINTS should be small enough to fit in a single + digit; with the current values this forces PyLong_SHIFT >= 9 + + The values 15 and 30 should fit all of the above requirements, on any + platform. +*/ + +#if PYLONG_BITS_IN_DIGIT == 30 +#if !(defined HAVE_UINT64_T && defined HAVE_UINT32_T && \ + defined HAVE_INT64_T && defined HAVE_INT32_T) +#error "30-bit long digits requested, but the necessary types are not available on this platform" +#endif +typedef PY_UINT32_T digit; +typedef PY_INT32_T sdigit; /* signed variant of digit */ +typedef PY_UINT64_T twodigits; +typedef PY_INT64_T stwodigits; /* signed variant of twodigits */ +#define PyLong_SHIFT 30 +#define _PyLong_DECIMAL_SHIFT 9 /* max(e such that 10**e fits in a digit) */ +#define _PyLong_DECIMAL_BASE ((digit)1000000000) /* 10 ** DECIMAL_SHIFT */ +#elif PYLONG_BITS_IN_DIGIT == 15 +typedef unsigned short digit; +typedef short sdigit; /* signed variant of digit */ +typedef unsigned long twodigits; +typedef long stwodigits; /* signed variant of twodigits */ +#define PyLong_SHIFT 15 +#define _PyLong_DECIMAL_SHIFT 4 /* max(e such that 10**e fits in a digit) */ +#define _PyLong_DECIMAL_BASE ((digit)10000) /* 10 ** DECIMAL_SHIFT */ +#else +#error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +#endif +#define PyLong_BASE ((digit)1 << PyLong_SHIFT) +#define PyLong_MASK ((digit)(PyLong_BASE - 1)) + +#if PyLong_SHIFT % 5 != 0 +#error "longobject.c requires that PyLong_SHIFT be divisible by 5" +#endif + +/* Long integer representation. + The absolute value of a number is equal to + SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) + Negative numbers are represented with ob_size < 0; + zero is represented by ob_size == 0. + In a normalized number, ob_digit[abs(ob_size)-1] (the most significant + digit) is never zero. Also, in all cases, for all valid i, + 0 <= ob_digit[i] <= MASK. + The allocation function takes care of allocating extra memory + so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available. + + CAUTION: Generic code manipulating subtypes of PyVarObject has to + aware that ints abuse ob_size's sign bit. +*/ + +struct _longobject { + PyObject_VAR_HEAD + digit ob_digit[1]; +}; + +PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); + +/* Return a copy of src. */ +PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LONGINTREPR_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/longobject.h b/libs/nxpy/include/longobject.h index 2a2eecf1..2c7470da 100644 --- a/libs/nxpy/include/longobject.h +++ b/libs/nxpy/include/longobject.h @@ -1,207 +1,207 @@ -#ifndef Py_LONGOBJECT_H -#define Py_LONGOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Long (arbitrary precision) integer object interface */ - -typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ - -PyAPI_DATA(PyTypeObject) PyLong_Type; - -#define PyLong_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS) -#define PyLong_CheckExact(op) (Py_TYPE(op) == &PyLong_Type) - -PyAPI_FUNC(PyObject *) PyLong_FromLong(long); -PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); -PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); -PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); -PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); -PyAPI_FUNC(long) PyLong_AsLong(PyObject *); -PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *); -PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *); -PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); -PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); -PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyLong_GetInfo(void); - -/* It may be useful in the future. I've added it in the PyInt -> PyLong - cleanup to keep the extra information. [CH] */ -#define PyLong_AS_LONG(op) PyLong_AsLong(op) - -/* Issue #1983: pid_t can be longer than a C long on some systems */ -#if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT -#define _Py_PARSE_PID "i" -#define PyLong_FromPid PyLong_FromLong -#define PyLong_AsPid PyLong_AsLong -#elif SIZEOF_PID_T == SIZEOF_LONG -#define _Py_PARSE_PID "l" -#define PyLong_FromPid PyLong_FromLong -#define PyLong_AsPid PyLong_AsLong -#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG -#define _Py_PARSE_PID "L" -#define PyLong_FromPid PyLong_FromLongLong -#define PyLong_AsPid PyLong_AsLongLong -#else -#error "sizeof(pid_t) is neither sizeof(int), sizeof(long) or sizeof(long long)" -#endif /* SIZEOF_PID_T */ - -#if SIZEOF_VOID_P == SIZEOF_INT -# define _Py_PARSE_INTPTR "i" -# define _Py_PARSE_UINTPTR "I" -#elif SIZEOF_VOID_P == SIZEOF_LONG -# define _Py_PARSE_INTPTR "l" -# define _Py_PARSE_UINTPTR "k" -#elif defined(SIZEOF_LONG_LONG) && SIZEOF_VOID_P == SIZEOF_LONG_LONG -# define _Py_PARSE_INTPTR "L" -# define _Py_PARSE_UINTPTR "K" -#else -# error "void* different in size from int, long and long long" -#endif /* SIZEOF_VOID_P */ - -/* Used by Python/mystrtoul.c. */ -#ifndef Py_LIMITED_API -PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; -#endif - -/* _PyLong_Frexp returns a double x and an exponent e such that the - true value is approximately equal to x * 2**e. e is >= 0. x is - 0.0 if and only if the input is 0 (in which case, e and x are both - zeroes); otherwise, 0.5 <= abs(x) < 1.0. On overflow, which is - possible if the number of bits doesn't fit into a Py_ssize_t, sets - OverflowError and returns -1.0 for x, 0 for e. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e); -#endif - -PyAPI_FUNC(double) PyLong_AsDouble(PyObject *); -PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *); -PyAPI_FUNC(void *) PyLong_AsVoidPtr(PyObject *); - -#ifdef HAVE_LONG_LONG -PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG); -PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG); -PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *); -PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *); -PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); -PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *); -#endif /* HAVE_LONG_LONG */ - -PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, Py_ssize_t, int); -PyAPI_FUNC(PyObject *) PyLong_FromUnicodeObject(PyObject *u, int base); -PyAPI_FUNC(PyObject *) _PyLong_FromBytes(const char *, Py_ssize_t, int); -#endif - -#ifndef Py_LIMITED_API -/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0. - v must not be NULL, and must be a normalized long. - There are no error cases. -*/ -PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); - - -/* _PyLong_NumBits. Return the number of bits needed to represent the - absolute value of a long. For example, this returns 1 for 1 and -1, 2 - for 2 and -2, and 2 for 3 and -3. It returns 0 for 0. - v must not be NULL, and must be a normalized long. - (size_t)-1 is returned and OverflowError set if the true result doesn't - fit in a size_t. -*/ -PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v); - -/* _PyLong_DivmodNear. Given integers a and b, compute the nearest - integer q to the exact quotient a / b, rounding to the nearest even integer - in the case of a tie. Return (q, r), where r = a - q*b. The remainder r - will satisfy abs(r) <= abs(b)/2, with equality possible only if q is - even. -*/ -PyAPI_FUNC(PyObject *) _PyLong_DivmodNear(PyObject *, PyObject *); - -/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in - base 256, and return a Python int with the same numeric value. - If n is 0, the integer is 0. Else: - If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB; - else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the - LSB. - If is_signed is 0/false, view the bytes as a non-negative integer. - If is_signed is 1/true, view the bytes as a 2's-complement integer, - non-negative if bit 0x80 of the MSB is clear, negative if set. - Error returns: - + Return NULL with the appropriate exception set if there's not - enough memory to create the Python int. -*/ -PyAPI_FUNC(PyObject *) _PyLong_FromByteArray( - const unsigned char* bytes, size_t n, - int little_endian, int is_signed); - -/* _PyLong_AsByteArray: Convert the least-significant 8*n bits of long - v to a base-256 integer, stored in array bytes. Normally return 0, - return -1 on error. - If little_endian is 1/true, store the MSB at bytes[n-1] and the LSB at - bytes[0]; else (little_endian is 0/false) store the MSB at bytes[0] and - the LSB at bytes[n-1]. - If is_signed is 0/false, it's an error if v < 0; else (v >= 0) n bytes - are filled and there's nothing special about bit 0x80 of the MSB. - If is_signed is 1/true, bytes is filled with the 2's-complement - representation of v's value. Bit 0x80 of the MSB is the sign bit. - Error returns (-1): - + is_signed is 0 and v < 0. TypeError is set in this case, and bytes - isn't altered. - + n isn't big enough to hold the full mathematical value of v. For - example, if is_signed is 0 and there are more digits in the v than - fit in n; or if is_signed is 1, v < 0, and n is just 1 bit shy of - being large enough to hold a sign bit. OverflowError is set in this - case, but bytes holds the least-significant n bytes of the true value. -*/ -PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v, - unsigned char* bytes, size_t n, - int little_endian, int is_signed); - -/* _PyLong_FromNbInt: Convert the given object to a PyLongObject - using the nb_int slot, if available. Raise TypeError if either the - nb_int slot is not available or the result of the call to nb_int - returns something not of type int. -*/ -PyAPI_FUNC(PyLongObject *)_PyLong_FromNbInt(PyObject *); - -/* _PyLong_Format: Convert the long to a string object with given base, - appending a base prefix of 0[box] if base is 2, 8 or 16. */ -PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *obj, int base); - -PyAPI_FUNC(int) _PyLong_FormatWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - int base, - int alternate); - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyLong_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif /* Py_LIMITED_API */ - -/* These aren't really part of the int object, but they're handy. The - functions are in Python/mystrtoul.c. - */ -PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); -PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); - -/* For use by the gcd function in mathmodule.c */ -PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_LONGOBJECT_H */ +#ifndef Py_LONGOBJECT_H +#define Py_LONGOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Long (arbitrary precision) integer object interface */ + +typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ + +PyAPI_DATA(PyTypeObject) PyLong_Type; + +#define PyLong_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS) +#define PyLong_CheckExact(op) (Py_TYPE(op) == &PyLong_Type) + +PyAPI_FUNC(PyObject *) PyLong_FromLong(long); +PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); +PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); +PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); +PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); +PyAPI_FUNC(long) PyLong_AsLong(PyObject *); +PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *); +PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *); +PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *); +PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); +PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyLong_AsInt(PyObject *); +#endif +PyAPI_FUNC(PyObject *) PyLong_GetInfo(void); + +/* It may be useful in the future. I've added it in the PyInt -> PyLong + cleanup to keep the extra information. [CH] */ +#define PyLong_AS_LONG(op) PyLong_AsLong(op) + +/* Issue #1983: pid_t can be longer than a C long on some systems */ +#if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT +#define _Py_PARSE_PID "i" +#define PyLong_FromPid PyLong_FromLong +#define PyLong_AsPid PyLong_AsLong +#elif SIZEOF_PID_T == SIZEOF_LONG +#define _Py_PARSE_PID "l" +#define PyLong_FromPid PyLong_FromLong +#define PyLong_AsPid PyLong_AsLong +#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG +#define _Py_PARSE_PID "L" +#define PyLong_FromPid PyLong_FromLongLong +#define PyLong_AsPid PyLong_AsLongLong +#else +#error "sizeof(pid_t) is neither sizeof(int), sizeof(long) or sizeof(long long)" +#endif /* SIZEOF_PID_T */ + +#if SIZEOF_VOID_P == SIZEOF_INT +# define _Py_PARSE_INTPTR "i" +# define _Py_PARSE_UINTPTR "I" +#elif SIZEOF_VOID_P == SIZEOF_LONG +# define _Py_PARSE_INTPTR "l" +# define _Py_PARSE_UINTPTR "k" +#elif defined(SIZEOF_LONG_LONG) && SIZEOF_VOID_P == SIZEOF_LONG_LONG +# define _Py_PARSE_INTPTR "L" +# define _Py_PARSE_UINTPTR "K" +#else +# error "void* different in size from int, long and long long" +#endif /* SIZEOF_VOID_P */ + +/* Used by Python/mystrtoul.c. */ +#ifndef Py_LIMITED_API +PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; +#endif + +/* _PyLong_Frexp returns a double x and an exponent e such that the + true value is approximately equal to x * 2**e. e is >= 0. x is + 0.0 if and only if the input is 0 (in which case, e and x are both + zeroes); otherwise, 0.5 <= abs(x) < 1.0. On overflow, which is + possible if the number of bits doesn't fit into a Py_ssize_t, sets + OverflowError and returns -1.0 for x, 0 for e. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e); +#endif + +PyAPI_FUNC(double) PyLong_AsDouble(PyObject *); +PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *); +PyAPI_FUNC(void *) PyLong_AsVoidPtr(PyObject *); + +#ifdef HAVE_LONG_LONG +PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG); +PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG); +PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *); +PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *); +PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); +PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *); +#endif /* HAVE_LONG_LONG */ + +PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, Py_ssize_t, int); +PyAPI_FUNC(PyObject *) PyLong_FromUnicodeObject(PyObject *u, int base); +PyAPI_FUNC(PyObject *) _PyLong_FromBytes(const char *, Py_ssize_t, int); +#endif + +#ifndef Py_LIMITED_API +/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0. + v must not be NULL, and must be a normalized long. + There are no error cases. +*/ +PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); + + +/* _PyLong_NumBits. Return the number of bits needed to represent the + absolute value of a long. For example, this returns 1 for 1 and -1, 2 + for 2 and -2, and 2 for 3 and -3. It returns 0 for 0. + v must not be NULL, and must be a normalized long. + (size_t)-1 is returned and OverflowError set if the true result doesn't + fit in a size_t. +*/ +PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v); + +/* _PyLong_DivmodNear. Given integers a and b, compute the nearest + integer q to the exact quotient a / b, rounding to the nearest even integer + in the case of a tie. Return (q, r), where r = a - q*b. The remainder r + will satisfy abs(r) <= abs(b)/2, with equality possible only if q is + even. +*/ +PyAPI_FUNC(PyObject *) _PyLong_DivmodNear(PyObject *, PyObject *); + +/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in + base 256, and return a Python int with the same numeric value. + If n is 0, the integer is 0. Else: + If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB; + else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the + LSB. + If is_signed is 0/false, view the bytes as a non-negative integer. + If is_signed is 1/true, view the bytes as a 2's-complement integer, + non-negative if bit 0x80 of the MSB is clear, negative if set. + Error returns: + + Return NULL with the appropriate exception set if there's not + enough memory to create the Python int. +*/ +PyAPI_FUNC(PyObject *) _PyLong_FromByteArray( + const unsigned char* bytes, size_t n, + int little_endian, int is_signed); + +/* _PyLong_AsByteArray: Convert the least-significant 8*n bits of long + v to a base-256 integer, stored in array bytes. Normally return 0, + return -1 on error. + If little_endian is 1/true, store the MSB at bytes[n-1] and the LSB at + bytes[0]; else (little_endian is 0/false) store the MSB at bytes[0] and + the LSB at bytes[n-1]. + If is_signed is 0/false, it's an error if v < 0; else (v >= 0) n bytes + are filled and there's nothing special about bit 0x80 of the MSB. + If is_signed is 1/true, bytes is filled with the 2's-complement + representation of v's value. Bit 0x80 of the MSB is the sign bit. + Error returns (-1): + + is_signed is 0 and v < 0. TypeError is set in this case, and bytes + isn't altered. + + n isn't big enough to hold the full mathematical value of v. For + example, if is_signed is 0 and there are more digits in the v than + fit in n; or if is_signed is 1, v < 0, and n is just 1 bit shy of + being large enough to hold a sign bit. OverflowError is set in this + case, but bytes holds the least-significant n bytes of the true value. +*/ +PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed); + +/* _PyLong_FromNbInt: Convert the given object to a PyLongObject + using the nb_int slot, if available. Raise TypeError if either the + nb_int slot is not available or the result of the call to nb_int + returns something not of type int. +*/ +PyAPI_FUNC(PyLongObject *)_PyLong_FromNbInt(PyObject *); + +/* _PyLong_Format: Convert the long to a string object with given base, + appending a base prefix of 0[box] if base is 2, 8 or 16. */ +PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *obj, int base); + +PyAPI_FUNC(int) _PyLong_FormatWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + int base, + int alternate); + +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +PyAPI_FUNC(int) _PyLong_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); +#endif /* Py_LIMITED_API */ + +/* These aren't really part of the int object, but they're handy. The + functions are in Python/mystrtoul.c. + */ +PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); +PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); + +/* For use by the gcd function in mathmodule.c */ +PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LONGOBJECT_H */ diff --git a/libs/nxpy/include/marshal.h b/libs/nxpy/include/marshal.h index 09d9337e..de9dfbbf 100644 --- a/libs/nxpy/include/marshal.h +++ b/libs/nxpy/include/marshal.h @@ -1,28 +1,28 @@ - -/* Interface for marshal.c */ - -#ifndef Py_MARSHAL_H -#define Py_MARSHAL_H -#ifdef __cplusplus -extern "C" { -#endif - -#define Py_MARSHAL_VERSION 4 - -PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); -PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); -PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); -PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); -PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); -#endif -PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, - Py_ssize_t); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MARSHAL_H */ + +/* Interface for marshal.c */ + +#ifndef Py_MARSHAL_H +#define Py_MARSHAL_H +#ifdef __cplusplus +extern "C" { +#endif + +#define Py_MARSHAL_VERSION 4 + +PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); +PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); +PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); +PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); +#endif +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, + Py_ssize_t); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MARSHAL_H */ diff --git a/libs/nxpy/include/memoryobject.h b/libs/nxpy/include/memoryobject.h index ab5ee095..ba677775 100644 --- a/libs/nxpy/include/memoryobject.h +++ b/libs/nxpy/include/memoryobject.h @@ -1,70 +1,70 @@ -/* Memory view object. In Python this is available as "memoryview". */ - -#ifndef Py_MEMORYOBJECT_H -#define Py_MEMORYOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_DATA(PyTypeObject) _PyManagedBuffer_Type; -#endif -PyAPI_DATA(PyTypeObject) PyMemoryView_Type; - -#define PyMemoryView_Check(op) (Py_TYPE(op) == &PyMemoryView_Type) - -#ifndef Py_LIMITED_API -/* Get a pointer to the memoryview's private copy of the exporter's buffer. */ -#define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view) -/* Get a pointer to the exporting object (this may be NULL!). */ -#define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj) -#endif - -PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base); -PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(char *mem, Py_ssize_t size, - int flags); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyMemoryView_FromBuffer(Py_buffer *info); -#endif -PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, - int buffertype, - char order); - - -/* The structs are declared here so that macros can work, but they shouldn't - be considered public. Don't access their fields directly, use the macros - and functions instead! */ -#ifndef Py_LIMITED_API -#define _Py_MANAGED_BUFFER_RELEASED 0x001 /* access to exporter blocked */ -#define _Py_MANAGED_BUFFER_FREE_FORMAT 0x002 /* free format */ -typedef struct { - PyObject_HEAD - int flags; /* state flags */ - Py_ssize_t exports; /* number of direct memoryview exports */ - Py_buffer master; /* snapshot buffer obtained from the original exporter */ -} _PyManagedBufferObject; - - -/* memoryview state flags */ -#define _Py_MEMORYVIEW_RELEASED 0x001 /* access to master buffer blocked */ -#define _Py_MEMORYVIEW_C 0x002 /* C-contiguous layout */ -#define _Py_MEMORYVIEW_FORTRAN 0x004 /* Fortran contiguous layout */ -#define _Py_MEMORYVIEW_SCALAR 0x008 /* scalar: ndim = 0 */ -#define _Py_MEMORYVIEW_PIL 0x010 /* PIL-style layout */ - -typedef struct { - PyObject_VAR_HEAD - _PyManagedBufferObject *mbuf; /* managed buffer */ - Py_hash_t hash; /* hash value for read-only views */ - int flags; /* state flags */ - Py_ssize_t exports; /* number of buffer re-exports */ - Py_buffer view; /* private copy of the exporter's view */ - PyObject *weakreflist; - Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */ -} PyMemoryViewObject; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MEMORYOBJECT_H */ +/* Memory view object. In Python this is available as "memoryview". */ + +#ifndef Py_MEMORYOBJECT_H +#define Py_MEMORYOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +PyAPI_DATA(PyTypeObject) _PyManagedBuffer_Type; +#endif +PyAPI_DATA(PyTypeObject) PyMemoryView_Type; + +#define PyMemoryView_Check(op) (Py_TYPE(op) == &PyMemoryView_Type) + +#ifndef Py_LIMITED_API +/* Get a pointer to the memoryview's private copy of the exporter's buffer. */ +#define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view) +/* Get a pointer to the exporting object (this may be NULL!). */ +#define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj) +#endif + +PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base); +PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(char *mem, Py_ssize_t size, + int flags); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyMemoryView_FromBuffer(Py_buffer *info); +#endif +PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, + int buffertype, + char order); + + +/* The structs are declared here so that macros can work, but they shouldn't + be considered public. Don't access their fields directly, use the macros + and functions instead! */ +#ifndef Py_LIMITED_API +#define _Py_MANAGED_BUFFER_RELEASED 0x001 /* access to exporter blocked */ +#define _Py_MANAGED_BUFFER_FREE_FORMAT 0x002 /* free format */ +typedef struct { + PyObject_HEAD + int flags; /* state flags */ + Py_ssize_t exports; /* number of direct memoryview exports */ + Py_buffer master; /* snapshot buffer obtained from the original exporter */ +} _PyManagedBufferObject; + + +/* memoryview state flags */ +#define _Py_MEMORYVIEW_RELEASED 0x001 /* access to master buffer blocked */ +#define _Py_MEMORYVIEW_C 0x002 /* C-contiguous layout */ +#define _Py_MEMORYVIEW_FORTRAN 0x004 /* Fortran contiguous layout */ +#define _Py_MEMORYVIEW_SCALAR 0x008 /* scalar: ndim = 0 */ +#define _Py_MEMORYVIEW_PIL 0x010 /* PIL-style layout */ + +typedef struct { + PyObject_VAR_HEAD + _PyManagedBufferObject *mbuf; /* managed buffer */ + Py_hash_t hash; /* hash value for read-only views */ + int flags; /* state flags */ + Py_ssize_t exports; /* number of buffer re-exports */ + Py_buffer view; /* private copy of the exporter's view */ + PyObject *weakreflist; + Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */ +} PyMemoryViewObject; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MEMORYOBJECT_H */ diff --git a/libs/nxpy/include/metagrammar.h b/libs/nxpy/include/metagrammar.h index 15c8ef8f..1fb471a0 100644 --- a/libs/nxpy/include/metagrammar.h +++ b/libs/nxpy/include/metagrammar.h @@ -1,18 +1,18 @@ -#ifndef Py_METAGRAMMAR_H -#define Py_METAGRAMMAR_H -#ifdef __cplusplus -extern "C" { -#endif - - -#define MSTART 256 -#define RULE 257 -#define RHS 258 -#define ALT 259 -#define ITEM 260 -#define ATOM 261 - -#ifdef __cplusplus -} -#endif -#endif /* !Py_METAGRAMMAR_H */ +#ifndef Py_METAGRAMMAR_H +#define Py_METAGRAMMAR_H +#ifdef __cplusplus +extern "C" { +#endif + + +#define MSTART 256 +#define RULE 257 +#define RHS 258 +#define ALT 259 +#define ITEM 260 +#define ATOM 261 + +#ifdef __cplusplus +} +#endif +#endif /* !Py_METAGRAMMAR_H */ diff --git a/libs/nxpy/include/methodobject.h b/libs/nxpy/include/methodobject.h index e2ad8044..f537ccbe 100644 --- a/libs/nxpy/include/methodobject.h +++ b/libs/nxpy/include/methodobject.h @@ -1,94 +1,94 @@ - -/* Method object interface */ - -#ifndef Py_METHODOBJECT_H -#define Py_METHODOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* This is about the type 'builtin_function_or_method', - not Python methods in user-defined classes. See classobject.h - for the latter. */ - -PyAPI_DATA(PyTypeObject) PyCFunction_Type; - -#define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type) - -typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); -typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, - PyObject *); -typedef PyObject *(*PyNoArgsFunction)(PyObject *); - -PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *); -PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *); -PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); - -/* Macros for direct access to these values. Type checks are *not* - done, so use with care. */ -#ifndef Py_LIMITED_API -#define PyCFunction_GET_FUNCTION(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_meth) -#define PyCFunction_GET_SELF(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \ - NULL : ((PyCFunctionObject *)func) -> m_self) -#define PyCFunction_GET_FLAGS(func) \ - (((PyCFunctionObject *)func) -> m_ml -> ml_flags) -#endif -PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); - -struct PyMethodDef { - const char *ml_name; /* The name of the built-in function/method */ - PyCFunction ml_meth; /* The C function that implements it */ - int ml_flags; /* Combination of METH_xxx flags, which mostly - describe the args expected by the C func */ - const char *ml_doc; /* The __doc__ attribute, or NULL */ -}; -typedef struct PyMethodDef PyMethodDef; - -#define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) -PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *, - PyObject *); - -/* Flag passed to newmethodobject */ -/* #define METH_OLDARGS 0x0000 -- unsupported now */ -#define METH_VARARGS 0x0001 -#define METH_KEYWORDS 0x0002 -/* METH_NOARGS and METH_O must not be combined with the flags above. */ -#define METH_NOARGS 0x0004 -#define METH_O 0x0008 - -/* METH_CLASS and METH_STATIC are a little different; these control - the construction of methods for a class. These cannot be used for - functions in modules. */ -#define METH_CLASS 0x0010 -#define METH_STATIC 0x0020 - -/* METH_COEXIST allows a method to be entered even though a slot has - already filled the entry. When defined, the flag allows a separate - method, "__contains__" for example, to coexist with a defined - slot like sq_contains. */ - -#define METH_COEXIST 0x0040 - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - PyMethodDef *m_ml; /* Description of the C function to call */ - PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ - PyObject *m_module; /* The __module__ attribute, can be anything */ - PyObject *m_weakreflist; /* List of weak references */ -} PyCFunctionObject; -#endif - -PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out); -PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_METHODOBJECT_H */ + +/* Method object interface */ + +#ifndef Py_METHODOBJECT_H +#define Py_METHODOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* This is about the type 'builtin_function_or_method', + not Python methods in user-defined classes. See classobject.h + for the latter. */ + +PyAPI_DATA(PyTypeObject) PyCFunction_Type; + +#define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type) + +typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); +typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, + PyObject *); +typedef PyObject *(*PyNoArgsFunction)(PyObject *); + +PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *); +PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *); +PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#ifndef Py_LIMITED_API +#define PyCFunction_GET_FUNCTION(func) \ + (((PyCFunctionObject *)func) -> m_ml -> ml_meth) +#define PyCFunction_GET_SELF(func) \ + (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \ + NULL : ((PyCFunctionObject *)func) -> m_self) +#define PyCFunction_GET_FLAGS(func) \ + (((PyCFunctionObject *)func) -> m_ml -> ml_flags) +#endif +PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); + +struct PyMethodDef { + const char *ml_name; /* The name of the built-in function/method */ + PyCFunction ml_meth; /* The C function that implements it */ + int ml_flags; /* Combination of METH_xxx flags, which mostly + describe the args expected by the C func */ + const char *ml_doc; /* The __doc__ attribute, or NULL */ +}; +typedef struct PyMethodDef PyMethodDef; + +#define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) +PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *, + PyObject *); + +/* Flag passed to newmethodobject */ +/* #define METH_OLDARGS 0x0000 -- unsupported now */ +#define METH_VARARGS 0x0001 +#define METH_KEYWORDS 0x0002 +/* METH_NOARGS and METH_O must not be combined with the flags above. */ +#define METH_NOARGS 0x0004 +#define METH_O 0x0008 + +/* METH_CLASS and METH_STATIC are a little different; these control + the construction of methods for a class. These cannot be used for + functions in modules. */ +#define METH_CLASS 0x0010 +#define METH_STATIC 0x0020 + +/* METH_COEXIST allows a method to be entered even though a slot has + already filled the entry. When defined, the flag allows a separate + method, "__contains__" for example, to coexist with a defined + slot like sq_contains. */ + +#define METH_COEXIST 0x0040 + +#ifndef Py_LIMITED_API +typedef struct { + PyObject_HEAD + PyMethodDef *m_ml; /* Description of the C function to call */ + PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ + PyObject *m_module; /* The __module__ attribute, can be anything */ + PyObject *m_weakreflist; /* List of weak references */ +} PyCFunctionObject; +#endif + +PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out); +PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_METHODOBJECT_H */ diff --git a/libs/nxpy/include/modsupport.h b/libs/nxpy/include/modsupport.h index 829aaf85..67d39839 100644 --- a/libs/nxpy/include/modsupport.h +++ b/libs/nxpy/include/modsupport.h @@ -1,155 +1,155 @@ - -#ifndef Py_MODSUPPORT_H -#define Py_MODSUPPORT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Module support interface */ - -#include - -/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier - to mean Py_ssize_t */ -#ifdef PY_SSIZE_T_CLEAN -#define PyArg_Parse _PyArg_Parse_SizeT -#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT -#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT -#define PyArg_VaParse _PyArg_VaParse_SizeT -#define PyArg_VaParseTupleAndKeywords _PyArg_VaParseTupleAndKeywords_SizeT -#define Py_BuildValue _Py_BuildValue_SizeT -#define Py_VaBuildValue _Py_VaBuildValue_SizeT -#else -PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); -#endif - -/* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */ -#if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); -PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); -PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, ...); -PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); -PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); -PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); -PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); -#endif -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw); -PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); - -PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); -PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, va_list); -#endif -PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); - -PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); -PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); -PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); -#define PyModule_AddIntMacro(m, c) PyModule_AddIntConstant(m, #c, c) -#define PyModule_AddStringMacro(m, c) PyModule_AddStringConstant(m, #c, c) - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(int) PyModule_SetDocString(PyObject *, const char *); -PyAPI_FUNC(int) PyModule_AddFunctions(PyObject *, PyMethodDef *); -PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def); -#endif - -#define Py_CLEANUP_SUPPORTED 0x20000 - -#define PYTHON_API_VERSION 1013 -#define PYTHON_API_STRING "1013" -/* The API version is maintained (independently from the Python version) - so we can detect mismatches between the interpreter and dynamically - loaded modules. These are diagnosed by an error message but - the module is still loaded (because the mismatch can only be tested - after loading the module). The error message is intended to - explain the core dump a few seconds later. - - The symbol PYTHON_API_STRING defines the same value as a string - literal. *** PLEASE MAKE SURE THE DEFINITIONS MATCH. *** - - Please add a line or two to the top of this log for each API - version change: - - 22-Feb-2006 MvL 1013 PEP 353 - long indices for sequence lengths - - 19-Aug-2002 GvR 1012 Changes to string object struct for - interning changes, saving 3 bytes. - - 17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side - - 25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and - PyFrame_New(); Python 2.1a2 - - 14-Mar-2000 GvR 1009 Unicode API added - - 3-Jan-1999 GvR 1007 Decided to change back! (Don't reuse 1008!) - - 3-Dec-1998 GvR 1008 Python 1.5.2b1 - - 18-Jan-1997 GvR 1007 string interning and other speedups - - 11-Oct-1996 GvR renamed Py_Ellipses to Py_Ellipsis :-( - - 30-Jul-1996 GvR Slice and ellipses syntax added - - 23-Jul-1996 GvR For 1.4 -- better safe than sorry this time :-) - - 7-Nov-1995 GvR Keyword arguments (should've been done at 1.3 :-( ) - - 10-Jan-1995 GvR Renamed globals to new naming scheme - - 9-Jan-1995 GvR Initial version (incompatible with older API) -*/ - -/* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of - Python 3, it will stay at the value of 3; changes to the limited API - must be performed in a strictly backwards-compatible manner. */ -#define PYTHON_ABI_VERSION 3 -#define PYTHON_ABI_STRING "3" - -#ifdef Py_TRACE_REFS - /* When we are tracing reference counts, rename module creation functions so - modules compiled with incompatible settings will generate a - link-time error. */ - #define PyModule_Create2 PyModule_Create2TraceRefs - #define PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec2TraceRefs -#endif - -PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*, - int apiver); - -#ifdef Py_LIMITED_API -#define PyModule_Create(module) \ - PyModule_Create2(module, PYTHON_ABI_VERSION) -#else -#define PyModule_Create(module) \ - PyModule_Create2(module, PYTHON_API_VERSION) -#endif - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(PyObject *) PyModule_FromDefAndSpec2(PyModuleDef *def, - PyObject *spec, - int module_api_version); - -#ifdef Py_LIMITED_API -#define PyModule_FromDefAndSpec(module, spec) \ - PyModule_FromDefAndSpec2(module, spec, PYTHON_ABI_VERSION) -#else -#define PyModule_FromDefAndSpec(module, spec) \ - PyModule_FromDefAndSpec2(module, spec, PYTHON_API_VERSION) -#endif /* Py_LIMITED_API */ -#endif /* New in 3.5 */ - -#ifndef Py_LIMITED_API -PyAPI_DATA(char *) _Py_PackageContext; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MODSUPPORT_H */ + +#ifndef Py_MODSUPPORT_H +#define Py_MODSUPPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Module support interface */ + +#include + +/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier + to mean Py_ssize_t */ +#ifdef PY_SSIZE_T_CLEAN +#define PyArg_Parse _PyArg_Parse_SizeT +#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT +#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT +#define PyArg_VaParse _PyArg_VaParse_SizeT +#define PyArg_VaParseTupleAndKeywords _PyArg_VaParseTupleAndKeywords_SizeT +#define Py_BuildValue _Py_BuildValue_SizeT +#define Py_VaBuildValue _Py_VaBuildValue_SizeT +#else +PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); +#endif + +/* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */ +#if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); +PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); +PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, ...); +PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); +PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); +PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); +PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); +#endif +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw); +PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); + +PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); +PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, va_list); +#endif +PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); + +PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); +PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); +PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); +#define PyModule_AddIntMacro(m, c) PyModule_AddIntConstant(m, #c, c) +#define PyModule_AddStringMacro(m, c) PyModule_AddStringConstant(m, #c, c) + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +/* New in 3.5 */ +PyAPI_FUNC(int) PyModule_SetDocString(PyObject *, const char *); +PyAPI_FUNC(int) PyModule_AddFunctions(PyObject *, PyMethodDef *); +PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def); +#endif + +#define Py_CLEANUP_SUPPORTED 0x20000 + +#define PYTHON_API_VERSION 1013 +#define PYTHON_API_STRING "1013" +/* The API version is maintained (independently from the Python version) + so we can detect mismatches between the interpreter and dynamically + loaded modules. These are diagnosed by an error message but + the module is still loaded (because the mismatch can only be tested + after loading the module). The error message is intended to + explain the core dump a few seconds later. + + The symbol PYTHON_API_STRING defines the same value as a string + literal. *** PLEASE MAKE SURE THE DEFINITIONS MATCH. *** + + Please add a line or two to the top of this log for each API + version change: + + 22-Feb-2006 MvL 1013 PEP 353 - long indices for sequence lengths + + 19-Aug-2002 GvR 1012 Changes to string object struct for + interning changes, saving 3 bytes. + + 17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side + + 25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and + PyFrame_New(); Python 2.1a2 + + 14-Mar-2000 GvR 1009 Unicode API added + + 3-Jan-1999 GvR 1007 Decided to change back! (Don't reuse 1008!) + + 3-Dec-1998 GvR 1008 Python 1.5.2b1 + + 18-Jan-1997 GvR 1007 string interning and other speedups + + 11-Oct-1996 GvR renamed Py_Ellipses to Py_Ellipsis :-( + + 30-Jul-1996 GvR Slice and ellipses syntax added + + 23-Jul-1996 GvR For 1.4 -- better safe than sorry this time :-) + + 7-Nov-1995 GvR Keyword arguments (should've been done at 1.3 :-( ) + + 10-Jan-1995 GvR Renamed globals to new naming scheme + + 9-Jan-1995 GvR Initial version (incompatible with older API) +*/ + +/* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of + Python 3, it will stay at the value of 3; changes to the limited API + must be performed in a strictly backwards-compatible manner. */ +#define PYTHON_ABI_VERSION 3 +#define PYTHON_ABI_STRING "3" + +#ifdef Py_TRACE_REFS + /* When we are tracing reference counts, rename module creation functions so + modules compiled with incompatible settings will generate a + link-time error. */ + #define PyModule_Create2 PyModule_Create2TraceRefs + #define PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec2TraceRefs +#endif + +PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*, + int apiver); + +#ifdef Py_LIMITED_API +#define PyModule_Create(module) \ + PyModule_Create2(module, PYTHON_ABI_VERSION) +#else +#define PyModule_Create(module) \ + PyModule_Create2(module, PYTHON_API_VERSION) +#endif + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +/* New in 3.5 */ +PyAPI_FUNC(PyObject *) PyModule_FromDefAndSpec2(PyModuleDef *def, + PyObject *spec, + int module_api_version); + +#ifdef Py_LIMITED_API +#define PyModule_FromDefAndSpec(module, spec) \ + PyModule_FromDefAndSpec2(module, spec, PYTHON_ABI_VERSION) +#else +#define PyModule_FromDefAndSpec(module, spec) \ + PyModule_FromDefAndSpec2(module, spec, PYTHON_API_VERSION) +#endif /* Py_LIMITED_API */ +#endif /* New in 3.5 */ + +#ifndef Py_LIMITED_API +PyAPI_DATA(char *) _Py_PackageContext; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MODSUPPORT_H */ diff --git a/libs/nxpy/include/moduleobject.h b/libs/nxpy/include/moduleobject.h index b44fb9b9..6dbe3c20 100644 --- a/libs/nxpy/include/moduleobject.h +++ b/libs/nxpy/include/moduleobject.h @@ -1,85 +1,85 @@ - -/* Module object interface */ - -#ifndef Py_MODULEOBJECT_H -#define Py_MODULEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyModule_Type; - -#define PyModule_Check(op) PyObject_TypeCheck(op, &PyModule_Type) -#define PyModule_CheckExact(op) (Py_TYPE(op) == &PyModule_Type) - -PyAPI_FUNC(PyObject *) PyModule_NewObject( - PyObject *name - ); -PyAPI_FUNC(PyObject *) PyModule_New( - const char *name /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *); -PyAPI_FUNC(PyObject *) PyModule_GetNameObject(PyObject *); -PyAPI_FUNC(const char *) PyModule_GetName(PyObject *); -PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *); -PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyModule_Clear(PyObject *); -PyAPI_FUNC(void) _PyModule_ClearDict(PyObject *); -#endif -PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*); -PyAPI_FUNC(void*) PyModule_GetState(PyObject*); - -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -PyAPI_FUNC(PyObject *) PyModuleDef_Init(struct PyModuleDef*); -PyAPI_DATA(PyTypeObject) PyModuleDef_Type; -#endif - -typedef struct PyModuleDef_Base { - PyObject_HEAD - PyObject* (*m_init)(void); - Py_ssize_t m_index; - PyObject* m_copy; -} PyModuleDef_Base; - -#define PyModuleDef_HEAD_INIT { \ - PyObject_HEAD_INIT(NULL) \ - NULL, /* m_init */ \ - 0, /* m_index */ \ - NULL, /* m_copy */ \ - } - -struct PyModuleDef_Slot; -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -typedef struct PyModuleDef_Slot{ - int slot; - void *value; -} PyModuleDef_Slot; - -#define Py_mod_create 1 -#define Py_mod_exec 2 - -#ifndef Py_LIMITED_API -#define _Py_mod_LAST_SLOT 2 -#endif - -#endif /* New in 3.5 */ - -typedef struct PyModuleDef{ - PyModuleDef_Base m_base; - const char* m_name; - const char* m_doc; - Py_ssize_t m_size; - PyMethodDef *m_methods; - struct PyModuleDef_Slot* m_slots; - traverseproc m_traverse; - inquiry m_clear; - freefunc m_free; -} PyModuleDef; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_MODULEOBJECT_H */ + +/* Module object interface */ + +#ifndef Py_MODULEOBJECT_H +#define Py_MODULEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyModule_Type; + +#define PyModule_Check(op) PyObject_TypeCheck(op, &PyModule_Type) +#define PyModule_CheckExact(op) (Py_TYPE(op) == &PyModule_Type) + +PyAPI_FUNC(PyObject *) PyModule_NewObject( + PyObject *name + ); +PyAPI_FUNC(PyObject *) PyModule_New( + const char *name /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *); +PyAPI_FUNC(PyObject *) PyModule_GetNameObject(PyObject *); +PyAPI_FUNC(const char *) PyModule_GetName(PyObject *); +PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *); +PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyModule_Clear(PyObject *); +PyAPI_FUNC(void) _PyModule_ClearDict(PyObject *); +#endif +PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*); +PyAPI_FUNC(void*) PyModule_GetState(PyObject*); + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +/* New in 3.5 */ +PyAPI_FUNC(PyObject *) PyModuleDef_Init(struct PyModuleDef*); +PyAPI_DATA(PyTypeObject) PyModuleDef_Type; +#endif + +typedef struct PyModuleDef_Base { + PyObject_HEAD + PyObject* (*m_init)(void); + Py_ssize_t m_index; + PyObject* m_copy; +} PyModuleDef_Base; + +#define PyModuleDef_HEAD_INIT { \ + PyObject_HEAD_INIT(NULL) \ + NULL, /* m_init */ \ + 0, /* m_index */ \ + NULL, /* m_copy */ \ + } + +struct PyModuleDef_Slot; +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +/* New in 3.5 */ +typedef struct PyModuleDef_Slot{ + int slot; + void *value; +} PyModuleDef_Slot; + +#define Py_mod_create 1 +#define Py_mod_exec 2 + +#ifndef Py_LIMITED_API +#define _Py_mod_LAST_SLOT 2 +#endif + +#endif /* New in 3.5 */ + +typedef struct PyModuleDef{ + PyModuleDef_Base m_base; + const char* m_name; + const char* m_doc; + Py_ssize_t m_size; + PyMethodDef *m_methods; + struct PyModuleDef_Slot* m_slots; + traverseproc m_traverse; + inquiry m_clear; + freefunc m_free; +} PyModuleDef; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MODULEOBJECT_H */ diff --git a/libs/nxpy/include/namespaceobject.h b/libs/nxpy/include/namespaceobject.h index a412f052..52a045c9 100644 --- a/libs/nxpy/include/namespaceobject.h +++ b/libs/nxpy/include/namespaceobject.h @@ -1,17 +1,17 @@ - -/* simple namespace object interface */ - -#ifndef NAMESPACEOBJECT_H -#define NAMESPACEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) _PyNamespace_Type; - -PyAPI_FUNC(PyObject *) _PyNamespace_New(PyObject *kwds); - -#ifdef __cplusplus -} -#endif -#endif /* !NAMESPACEOBJECT_H */ + +/* simple namespace object interface */ + +#ifndef NAMESPACEOBJECT_H +#define NAMESPACEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) _PyNamespace_Type; + +PyAPI_FUNC(PyObject *) _PyNamespace_New(PyObject *kwds); + +#ifdef __cplusplus +} +#endif +#endif /* !NAMESPACEOBJECT_H */ diff --git a/libs/nxpy/include/node.h b/libs/nxpy/include/node.h index 654ad858..912a64b8 100644 --- a/libs/nxpy/include/node.h +++ b/libs/nxpy/include/node.h @@ -1,44 +1,44 @@ - -/* Parse tree node interface */ - -#ifndef Py_NODE_H -#define Py_NODE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _node { - short n_type; - char *n_str; - int n_lineno; - int n_col_offset; - int n_nchildren; - struct _node *n_child; -} node; - -PyAPI_FUNC(node *) PyNode_New(int type); -PyAPI_FUNC(int) PyNode_AddChild(node *n, int type, - char *str, int lineno, int col_offset); -PyAPI_FUNC(void) PyNode_Free(node *n); -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); -#endif - -/* Node access functions */ -#define NCH(n) ((n)->n_nchildren) - -#define CHILD(n, i) (&(n)->n_child[i]) -#define RCHILD(n, i) (CHILD(n, NCH(n) + i)) -#define TYPE(n) ((n)->n_type) -#define STR(n) ((n)->n_str) -#define LINENO(n) ((n)->n_lineno) - -/* Assert that the type of a node is what we expect */ -#define REQ(n, type) assert(TYPE(n) == (type)) - -PyAPI_FUNC(void) PyNode_ListTree(node *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_NODE_H */ + +/* Parse tree node interface */ + +#ifndef Py_NODE_H +#define Py_NODE_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _node { + short n_type; + char *n_str; + int n_lineno; + int n_col_offset; + int n_nchildren; + struct _node *n_child; +} node; + +PyAPI_FUNC(node *) PyNode_New(int type); +PyAPI_FUNC(int) PyNode_AddChild(node *n, int type, + char *str, int lineno, int col_offset); +PyAPI_FUNC(void) PyNode_Free(node *n); +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); +#endif + +/* Node access functions */ +#define NCH(n) ((n)->n_nchildren) + +#define CHILD(n, i) (&(n)->n_child[i]) +#define RCHILD(n, i) (CHILD(n, NCH(n) + i)) +#define TYPE(n) ((n)->n_type) +#define STR(n) ((n)->n_str) +#define LINENO(n) ((n)->n_lineno) + +/* Assert that the type of a node is what we expect */ +#define REQ(n, type) assert(TYPE(n) == (type)) + +PyAPI_FUNC(void) PyNode_ListTree(node *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_NODE_H */ diff --git a/libs/nxpy/include/object.h b/libs/nxpy/include/object.h index 50d9747c..88adf59d 100644 --- a/libs/nxpy/include/object.h +++ b/libs/nxpy/include/object.h @@ -1,1065 +1,1065 @@ -#ifndef Py_OBJECT_H -#define Py_OBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Object and type object interface */ - -/* -Objects are structures allocated on the heap. Special rules apply to -the use of objects to ensure they are properly garbage-collected. -Objects are never allocated statically or on the stack; they must be -accessed through special macros and functions only. (Type objects are -exceptions to the first rule; the standard types are represented by -statically initialized type objects, although work on type/class unification -for Python 2.2 made it possible to have heap-allocated type objects too). - -An object has a 'reference count' that is increased or decreased when a -pointer to the object is copied or deleted; when the reference count -reaches zero there are no references to the object left and it can be -removed from the heap. - -An object has a 'type' that determines what it represents and what kind -of data it contains. An object's type is fixed when it is created. -Types themselves are represented as objects; an object contains a -pointer to the corresponding type object. The type itself has a type -pointer pointing to the object representing the type 'type', which -contains a pointer to itself!). - -Objects do not float around in memory; once allocated an object keeps -the same size and address. Objects that must hold variable-size data -can contain pointers to variable-size parts of the object. Not all -objects of the same type have the same size; but the size cannot change -after allocation. (These restrictions are made so a reference to an -object can be simply a pointer -- moving an object would require -updating all the pointers, and changing an object's size would require -moving it if there was another object right next to it.) - -Objects are always accessed through pointers of the type 'PyObject *'. -The type 'PyObject' is a structure that only contains the reference count -and the type pointer. The actual memory allocated for an object -contains other data that can only be accessed after casting the pointer -to a pointer to a longer structure type. This longer type must start -with the reference count and type fields; the macro PyObject_HEAD should be -used for this (to accommodate for future changes). The implementation -of a particular object type can cast the object pointer to the proper -type and back. - -A standard interface exists for objects that contain an array of items -whose size is determined when the object is allocated. -*/ - -/* Py_DEBUG implies Py_TRACE_REFS. */ -#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS) -#define Py_TRACE_REFS -#endif - -/* Py_TRACE_REFS implies Py_REF_DEBUG. */ -#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) -#define Py_REF_DEBUG -#endif - -#if defined(Py_LIMITED_API) && defined(Py_REF_DEBUG) -#error Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG -#endif - - -#ifdef Py_TRACE_REFS -/* Define pointers to support a doubly-linked list of all live heap objects. */ -#define _PyObject_HEAD_EXTRA \ - struct _object *_ob_next; \ - struct _object *_ob_prev; - -#define _PyObject_EXTRA_INIT 0, 0, - -#else -#define _PyObject_HEAD_EXTRA -#define _PyObject_EXTRA_INIT -#endif - -/* PyObject_HEAD defines the initial segment of every PyObject. */ -#define PyObject_HEAD PyObject ob_base; - -#define PyObject_HEAD_INIT(type) \ - { _PyObject_EXTRA_INIT \ - 1, type }, - -#define PyVarObject_HEAD_INIT(type, size) \ - { PyObject_HEAD_INIT(type) size }, - -/* PyObject_VAR_HEAD defines the initial segment of all variable-size - * container objects. These end with a declaration of an array with 1 - * element, but enough space is malloc'ed so that the array actually - * has room for ob_size elements. Note that ob_size is an element count, - * not necessarily a byte count. - */ -#define PyObject_VAR_HEAD PyVarObject ob_base; -#define Py_INVALID_SIZE (Py_ssize_t)-1 - -/* Nothing is actually declared to be a PyObject, but every pointer to - * a Python object can be cast to a PyObject*. This is inheritance built - * by hand. Similarly every pointer to a variable-size Python object can, - * in addition, be cast to PyVarObject*. - */ -typedef struct _object { - _PyObject_HEAD_EXTRA - Py_ssize_t ob_refcnt; - struct _typeobject *ob_type; -} PyObject; - -typedef struct { - PyObject ob_base; - Py_ssize_t ob_size; /* Number of items in variable part */ -} PyVarObject; - -#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) -#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) - -/********************* String Literals ****************************************/ -/* This structure helps managing static strings. The basic usage goes like this: - Instead of doing - - r = PyObject_CallMethod(o, "foo", "args", ...); - - do - - _Py_IDENTIFIER(foo); - ... - r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...); - - PyId_foo is a static variable, either on block level or file level. On first - usage, the string "foo" is interned, and the structures are linked. On interpreter - shutdown, all strings are released (through _PyUnicode_ClearStaticStrings). - - Alternatively, _Py_static_string allows choosing the variable name. - _PyUnicode_FromId returns a borrowed reference to the interned string. - _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*. -*/ -typedef struct _Py_Identifier { - struct _Py_Identifier *next; - const char* string; - PyObject *object; -} _Py_Identifier; - -#define _Py_static_string_init(value) { 0, value, 0 } -#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value) -#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname) - -/* -Type objects contain a string containing the type name (to help somewhat -in debugging), the allocation parameters (see PyObject_New() and -PyObject_NewVar()), -and methods for accessing objects of the type. Methods are optional, a -nil pointer meaning that particular kind of access is not available for -this type. The Py_DECREF() macro uses the tp_dealloc method without -checking for a nil pointer; it should always be implemented except if -the implementation can guarantee that the reference count will never -reach zero (e.g., for statically allocated type objects). - -NB: the methods for certain type groups are now contained in separate -method blocks. -*/ - -typedef PyObject * (*unaryfunc)(PyObject *); -typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); -typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); -typedef int (*inquiry)(PyObject *); -typedef Py_ssize_t (*lenfunc)(PyObject *); -typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); -typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); -typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); -typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); -typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); - -#ifndef Py_LIMITED_API -/* buffer interface */ -typedef struct bufferinfo { - void *buf; - PyObject *obj; /* owned reference */ - Py_ssize_t len; - Py_ssize_t itemsize; /* This is Py_ssize_t so it can be - pointed to by strides in simple case.*/ - int readonly; - int ndim; - char *format; - Py_ssize_t *shape; - Py_ssize_t *strides; - Py_ssize_t *suboffsets; - void *internal; -} Py_buffer; - -typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); -typedef void (*releasebufferproc)(PyObject *, Py_buffer *); - -/* Maximum number of dimensions */ -#define PyBUF_MAX_NDIM 64 - -/* Flags for getting buffers */ -#define PyBUF_SIMPLE 0 -#define PyBUF_WRITABLE 0x0001 -/* we used to include an E, backwards compatible alias */ -#define PyBUF_WRITEABLE PyBUF_WRITABLE -#define PyBUF_FORMAT 0x0004 -#define PyBUF_ND 0x0008 -#define PyBUF_STRIDES (0x0010 | PyBUF_ND) -#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) -#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) -#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) -#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) - -#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) -#define PyBUF_CONTIG_RO (PyBUF_ND) - -#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) -#define PyBUF_STRIDED_RO (PyBUF_STRIDES) - -#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) - -#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) - - -#define PyBUF_READ 0x100 -#define PyBUF_WRITE 0x200 - -/* End buffer interface */ -#endif /* Py_LIMITED_API */ - -typedef int (*objobjproc)(PyObject *, PyObject *); -typedef int (*visitproc)(PyObject *, void *); -typedef int (*traverseproc)(PyObject *, visitproc, void *); - -#ifndef Py_LIMITED_API -typedef struct { - /* Number implementations must check *both* - arguments for proper type and implement the necessary conversions - in the slot functions themselves. */ - - binaryfunc nb_add; - binaryfunc nb_subtract; - binaryfunc nb_multiply; - binaryfunc nb_remainder; - binaryfunc nb_divmod; - ternaryfunc nb_power; - unaryfunc nb_negative; - unaryfunc nb_positive; - unaryfunc nb_absolute; - inquiry nb_bool; - unaryfunc nb_invert; - binaryfunc nb_lshift; - binaryfunc nb_rshift; - binaryfunc nb_and; - binaryfunc nb_xor; - binaryfunc nb_or; - unaryfunc nb_int; - void *nb_reserved; /* the slot formerly known as nb_long */ - unaryfunc nb_float; - - binaryfunc nb_inplace_add; - binaryfunc nb_inplace_subtract; - binaryfunc nb_inplace_multiply; - binaryfunc nb_inplace_remainder; - ternaryfunc nb_inplace_power; - binaryfunc nb_inplace_lshift; - binaryfunc nb_inplace_rshift; - binaryfunc nb_inplace_and; - binaryfunc nb_inplace_xor; - binaryfunc nb_inplace_or; - - binaryfunc nb_floor_divide; - binaryfunc nb_true_divide; - binaryfunc nb_inplace_floor_divide; - binaryfunc nb_inplace_true_divide; - - unaryfunc nb_index; - - binaryfunc nb_matrix_multiply; - binaryfunc nb_inplace_matrix_multiply; -} PyNumberMethods; - -typedef struct { - lenfunc sq_length; - binaryfunc sq_concat; - ssizeargfunc sq_repeat; - ssizeargfunc sq_item; - void *was_sq_slice; - ssizeobjargproc sq_ass_item; - void *was_sq_ass_slice; - objobjproc sq_contains; - - binaryfunc sq_inplace_concat; - ssizeargfunc sq_inplace_repeat; -} PySequenceMethods; - -typedef struct { - lenfunc mp_length; - binaryfunc mp_subscript; - objobjargproc mp_ass_subscript; -} PyMappingMethods; - -typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; -} PyAsyncMethods; - -typedef struct { - getbufferproc bf_getbuffer; - releasebufferproc bf_releasebuffer; -} PyBufferProcs; -#endif /* Py_LIMITED_API */ - -typedef void (*freefunc)(void *); -typedef void (*destructor)(PyObject *); -#ifndef Py_LIMITED_API -/* We can't provide a full compile-time check that limited-API - users won't implement tp_print. However, not defining printfunc - and making tp_print of a different function pointer type - should at least cause a warning in most cases. */ -typedef int (*printfunc)(PyObject *, FILE *, int); -#endif -typedef PyObject *(*getattrfunc)(PyObject *, char *); -typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); -typedef int (*setattrfunc)(PyObject *, char *, PyObject *); -typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); -typedef PyObject *(*reprfunc)(PyObject *); -typedef Py_hash_t (*hashfunc)(PyObject *); -typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); -typedef PyObject *(*getiterfunc) (PyObject *); -typedef PyObject *(*iternextfunc) (PyObject *); -typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); -typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); -typedef int (*initproc)(PyObject *, PyObject *, PyObject *); -typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); -typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t); - -#ifdef Py_LIMITED_API -typedef struct _typeobject PyTypeObject; /* opaque */ -#else -typedef struct _typeobject { - PyObject_VAR_HEAD - const char *tp_name; /* For printing, in format "." */ - Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ - - /* Methods to implement standard operations */ - - destructor tp_dealloc; - printfunc tp_print; - getattrfunc tp_getattr; - setattrfunc tp_setattr; - PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) - or tp_reserved (Python 3) */ - reprfunc tp_repr; - - /* Method suites for standard classes */ - - PyNumberMethods *tp_as_number; - PySequenceMethods *tp_as_sequence; - PyMappingMethods *tp_as_mapping; - - /* More standard operations (here for binary compatibility) */ - - hashfunc tp_hash; - ternaryfunc tp_call; - reprfunc tp_str; - getattrofunc tp_getattro; - setattrofunc tp_setattro; - - /* Functions to access object as input/output buffer */ - PyBufferProcs *tp_as_buffer; - - /* Flags to define presence of optional/expanded features */ - unsigned long tp_flags; - - const char *tp_doc; /* Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - traverseproc tp_traverse; - - /* delete references to contained objects */ - inquiry tp_clear; - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - richcmpfunc tp_richcompare; - - /* weak reference enabler */ - Py_ssize_t tp_weaklistoffset; - - /* Iterators */ - getiterfunc tp_iter; - iternextfunc tp_iternext; - - /* Attribute descriptor and subclassing stuff */ - struct PyMethodDef *tp_methods; - struct PyMemberDef *tp_members; - struct PyGetSetDef *tp_getset; - struct _typeobject *tp_base; - PyObject *tp_dict; - descrgetfunc tp_descr_get; - descrsetfunc tp_descr_set; - Py_ssize_t tp_dictoffset; - initproc tp_init; - allocfunc tp_alloc; - newfunc tp_new; - freefunc tp_free; /* Low-level free-memory routine */ - inquiry tp_is_gc; /* For PyObject_IS_GC */ - PyObject *tp_bases; - PyObject *tp_mro; /* method resolution order */ - PyObject *tp_cache; - PyObject *tp_subclasses; - PyObject *tp_weaklist; - destructor tp_del; - - /* Type attribute cache version tag. Added in version 2.6 */ - unsigned int tp_version_tag; - - destructor tp_finalize; - -#ifdef COUNT_ALLOCS - /* these must be last and never explicitly initialized */ - Py_ssize_t tp_allocs; - Py_ssize_t tp_frees; - Py_ssize_t tp_maxalloc; - struct _typeobject *tp_prev; - struct _typeobject *tp_next; -#endif -} PyTypeObject; -#endif - -typedef struct{ - int slot; /* slot id, see below */ - void *pfunc; /* function pointer */ -} PyType_Slot; - -typedef struct{ - const char* name; - int basicsize; - int itemsize; - unsigned int flags; - PyType_Slot *slots; /* terminated by slot==0. */ -} PyType_Spec; - -PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*); -#endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 -PyAPI_FUNC(void*) PyType_GetSlot(PyTypeObject*, int); -#endif - -#ifndef Py_LIMITED_API -/* The *real* layout of a type object when allocated on the heap */ -typedef struct _heaptypeobject { - /* Note: there's a dependency on the order of these members - in slotptr() in typeobject.c . */ - PyTypeObject ht_type; - PyAsyncMethods as_async; - PyNumberMethods as_number; - PyMappingMethods as_mapping; - PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, - so that the mapping wins when both - the mapping and the sequence define - a given operator (e.g. __getitem__). - see add_operators() in typeobject.c . */ - PyBufferProcs as_buffer; - PyObject *ht_name, *ht_slots, *ht_qualname; - struct _dictkeysobject *ht_cached_keys; - /* here are optional user slots, followed by the members. */ -} PyHeapTypeObject; - -/* access macro to the members which are floating "behind" the object */ -#define PyHeapType_GET_MEMBERS(etype) \ - ((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize)) -#endif - -/* Generic type check */ -PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *); -#define PyObject_TypeCheck(ob, tp) \ - (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp))) - -PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ -PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ -PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ - -PyAPI_FUNC(unsigned long) PyType_GetFlags(PyTypeObject*); - -#define PyType_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS) -#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type) - -PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); -PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t); -PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *, - PyObject *, PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); -PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *); -PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *); -PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *); -#endif -PyAPI_FUNC(unsigned int) PyType_ClearCache(void); -PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); -PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); -#endif - -/* Generic operations on objects */ -struct _Py_Identifier; -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); -PyAPI_FUNC(void) _Py_BreakPoint(void); -PyAPI_FUNC(void) _PyObject_Dump(PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_Bytes(PyObject *); -PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); -PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); -PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *); -PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); -PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); -PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *); -PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *); -PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *); -PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *); -#endif -PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, - PyObject *, PyObject *); -PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *); -PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *); -PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *); -PyAPI_FUNC(int) PyObject_IsTrue(PyObject *); -PyAPI_FUNC(int) PyObject_Not(PyObject *); -PyAPI_FUNC(int) PyCallable_Check(PyObject *); - -PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); -PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); -#endif - -/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes - dict as the last parameter. */ -PyAPI_FUNC(PyObject *) -_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(int) -_PyObject_GenericSetAttrWithDict(PyObject *, PyObject *, - PyObject *, PyObject *); - -/* Helper to look up a builtin object */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) -_PyObject_GetBuiltin(const char *name); -#endif - -/* PyObject_Dir(obj) acts like Python builtins.dir(obj), returning a - list of strings. PyObject_Dir(NULL) is like builtins.dir(), - returning the names of the current locals. In this case, if there are - no current locals, NULL is returned, and PyErr_Occurred() is false. -*/ -PyAPI_FUNC(PyObject *) PyObject_Dir(PyObject *); - - -/* Helpers for printing recursive container types */ -PyAPI_FUNC(int) Py_ReprEnter(PyObject *); -PyAPI_FUNC(void) Py_ReprLeave(PyObject *); - -/* Flag bits for printing: */ -#define Py_PRINT_RAW 1 /* No string quotes etc. */ - -/* -`Type flags (tp_flags) - -These flags are used to extend the type structure in a backwards-compatible -fashion. Extensions can use the flags to indicate (and test) when a given -type structure contains a new feature. The Python core will use these when -introducing new functionality between major revisions (to avoid mid-version -changes in the PYTHON_API_VERSION). - -Arbitration of the flag bit positions will need to be coordinated among -all extension writers who publically release their extensions (this will -be fewer than you might expect!).. - -Most flags were removed as of Python 3.0 to make room for new flags. (Some -flags are not for backwards compatibility but to indicate the presence of an -optional feature; these flags remain of course.) - -Type definitions should use Py_TPFLAGS_DEFAULT for their tp_flags value. - -Code can use PyType_HasFeature(type_ob, flag_value) to test whether the -given type object has a specified feature. -*/ - -/* Set if the type object is dynamically allocated */ -#define Py_TPFLAGS_HEAPTYPE (1UL << 9) - -/* Set if the type allows subclassing */ -#define Py_TPFLAGS_BASETYPE (1UL << 10) - -/* Set if the type is 'ready' -- fully initialized */ -#define Py_TPFLAGS_READY (1UL << 12) - -/* Set while the type is being 'readied', to prevent recursive ready calls */ -#define Py_TPFLAGS_READYING (1UL << 13) - -/* Objects support garbage collection (see objimp.h) */ -#define Py_TPFLAGS_HAVE_GC (1UL << 14) - -/* These two bits are preserved for Stackless Python, next after this is 17 */ -#ifdef STACKLESS -#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3UL << 15) -#else -#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0 -#endif - -/* Objects support type attribute cache */ -#define Py_TPFLAGS_HAVE_VERSION_TAG (1UL << 18) -#define Py_TPFLAGS_VALID_VERSION_TAG (1UL << 19) - -/* Type is abstract and cannot be instantiated */ -#define Py_TPFLAGS_IS_ABSTRACT (1UL << 20) - -/* These flags are used to determine if a type is a subclass. */ -#define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24) -#define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25) -#define Py_TPFLAGS_TUPLE_SUBCLASS (1UL << 26) -#define Py_TPFLAGS_BYTES_SUBCLASS (1UL << 27) -#define Py_TPFLAGS_UNICODE_SUBCLASS (1UL << 28) -#define Py_TPFLAGS_DICT_SUBCLASS (1UL << 29) -#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1UL << 30) -#define Py_TPFLAGS_TYPE_SUBCLASS (1UL << 31) - -#define Py_TPFLAGS_DEFAULT ( \ - Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ - Py_TPFLAGS_HAVE_VERSION_TAG | \ - 0) - -/* NOTE: The following flags reuse lower bits (removed as part of the - * Python 3.0 transition). */ - -/* Type structure has tp_finalize member (3.4) */ -#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0) - -#ifdef Py_LIMITED_API -#define PyType_HasFeature(t,f) ((PyType_GetFlags(t) & (f)) != 0) -#else -#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) -#endif -#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f) - - -/* -The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement -reference counts. Py_DECREF calls the object's deallocator function when -the refcount falls to 0; for -objects that don't contain references to other objects or heap memory -this can be the standard function free(). Both macros can be used -wherever a void expression is allowed. The argument must not be a -NULL pointer. If it may be NULL, use Py_XINCREF/Py_XDECREF instead. -The macro _Py_NewReference(op) initialize reference counts to 1, and -in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional -bookkeeping appropriate to the special build. - -We assume that the reference count field can never overflow; this can -be proven when the size of the field is the same as the pointer size, so -we ignore the possibility. Provided a C int is at least 32 bits (which -is implicitly assumed in many parts of this code), that's enough for -about 2**31 references to an object. - -XXX The following became out of date in Python 2.2, but I'm not sure -XXX what the full truth is now. Certainly, heap-allocated type objects -XXX can and should be deallocated. -Type objects should never be deallocated; the type pointer in an object -is not considered to be a reference to the type object, to save -complications in the deallocation function. (This is actually a -decision that's up to the implementer of each new type so if you want, -you can count such references to the type object.) -*/ - -/* First define a pile of simple helper macros, one set per special - * build symbol. These either expand to the obvious things, or to - * nothing at all when the special mode isn't in effect. The main - * macros can later be defined just once then, yet expand to different - * things depending on which special build options are and aren't in effect. - * Trust me : while painful, this is 20x easier to understand than, - * e.g, defining _Py_NewReference five different times in a maze of nested - * #ifdefs (we used to do that -- it was impenetrable). - */ -#ifdef Py_REF_DEBUG -PyAPI_DATA(Py_ssize_t) _Py_RefTotal; -PyAPI_FUNC(void) _Py_NegativeRefcount(const char *fname, - int lineno, PyObject *op); -PyAPI_FUNC(PyObject *) _PyDict_Dummy(void); -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); -#define _Py_INC_REFTOTAL _Py_RefTotal++ -#define _Py_DEC_REFTOTAL _Py_RefTotal-- -#define _Py_REF_DEBUG_COMMA , -#define _Py_CHECK_REFCNT(OP) \ -{ if (((PyObject*)OP)->ob_refcnt < 0) \ - _Py_NegativeRefcount(__FILE__, __LINE__, \ - (PyObject *)(OP)); \ -} -/* Py_REF_DEBUG also controls the display of refcounts and memory block - * allocations at the interactive prompt and at interpreter shutdown - */ -PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); -#define _PY_DEBUG_PRINT_TOTAL_REFS() _PyDebug_PrintTotalRefs() -#else -#define _Py_INC_REFTOTAL -#define _Py_DEC_REFTOTAL -#define _Py_REF_DEBUG_COMMA -#define _Py_CHECK_REFCNT(OP) /* a semicolon */; -#define _PY_DEBUG_PRINT_TOTAL_REFS() -#endif /* Py_REF_DEBUG */ - -#ifdef COUNT_ALLOCS -PyAPI_FUNC(void) inc_count(PyTypeObject *); -PyAPI_FUNC(void) dec_count(PyTypeObject *); -#define _Py_INC_TPALLOCS(OP) inc_count(Py_TYPE(OP)) -#define _Py_INC_TPFREES(OP) dec_count(Py_TYPE(OP)) -#define _Py_DEC_TPFREES(OP) Py_TYPE(OP)->tp_frees-- -#define _Py_COUNT_ALLOCS_COMMA , -#else -#define _Py_INC_TPALLOCS(OP) -#define _Py_INC_TPFREES(OP) -#define _Py_DEC_TPFREES(OP) -#define _Py_COUNT_ALLOCS_COMMA -#endif /* COUNT_ALLOCS */ - -#ifdef Py_TRACE_REFS -/* Py_TRACE_REFS is such major surgery that we call external routines. */ -PyAPI_FUNC(void) _Py_NewReference(PyObject *); -PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); -PyAPI_FUNC(void) _Py_Dealloc(PyObject *); -PyAPI_FUNC(void) _Py_PrintReferences(FILE *); -PyAPI_FUNC(void) _Py_PrintReferenceAddresses(FILE *); -PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); - -#else -/* Without Py_TRACE_REFS, there's little enough to do that we expand code - * inline. - */ -#define _Py_NewReference(op) ( \ - _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \ - _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ - Py_REFCNT(op) = 1) - -#define _Py_ForgetReference(op) _Py_INC_TPFREES(op) - -#ifdef Py_LIMITED_API -PyAPI_FUNC(void) _Py_Dealloc(PyObject *); -#else -#define _Py_Dealloc(op) ( \ - _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \ - (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op))) -#endif -#endif /* !Py_TRACE_REFS */ - -#define Py_INCREF(op) ( \ - _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ - ((PyObject *)(op))->ob_refcnt++) - -#define Py_DECREF(op) \ - do { \ - PyObject *_py_decref_tmp = (PyObject *)(op); \ - if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ - --(_py_decref_tmp)->ob_refcnt != 0) \ - _Py_CHECK_REFCNT(_py_decref_tmp) \ - else \ - _Py_Dealloc(_py_decref_tmp); \ - } while (0) - -/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear - * and tp_dealloc implementations. - * - * Note that "the obvious" code can be deadly: - * - * Py_XDECREF(op); - * op = NULL; - * - * Typically, `op` is something like self->containee, and `self` is done - * using its `containee` member. In the code sequence above, suppose - * `containee` is non-NULL with a refcount of 1. Its refcount falls to - * 0 on the first line, which can trigger an arbitrary amount of code, - * possibly including finalizers (like __del__ methods or weakref callbacks) - * coded in Python, which in turn can release the GIL and allow other threads - * to run, etc. Such code may even invoke methods of `self` again, or cause - * cyclic gc to trigger, but-- oops! --self->containee still points to the - * object being torn down, and it may be in an insane state while being torn - * down. This has in fact been a rich historic source of miserable (rare & - * hard-to-diagnose) segfaulting (and other) bugs. - * - * The safe way is: - * - * Py_CLEAR(op); - * - * That arranges to set `op` to NULL _before_ decref'ing, so that any code - * triggered as a side-effect of `op` getting torn down no longer believes - * `op` points to a valid object. - * - * There are cases where it's safe to use the naive code, but they're brittle. - * For example, if `op` points to a Python integer, you know that destroying - * one of those can't cause problems -- but in part that relies on that - * Python integers aren't currently weakly referencable. Best practice is - * to use Py_CLEAR() even if you can't think of a reason for why you need to. - */ -#define Py_CLEAR(op) \ - do { \ - PyObject *_py_tmp = (PyObject *)(op); \ - if (_py_tmp != NULL) { \ - (op) = NULL; \ - Py_DECREF(_py_tmp); \ - } \ - } while (0) - -/* Macros to use in case the object pointer may be NULL: */ -#define Py_XINCREF(op) \ - do { \ - PyObject *_py_xincref_tmp = (PyObject *)(op); \ - if (_py_xincref_tmp != NULL) \ - Py_INCREF(_py_xincref_tmp); \ - } while (0) - -#define Py_XDECREF(op) \ - do { \ - PyObject *_py_xdecref_tmp = (PyObject *)(op); \ - if (_py_xdecref_tmp != NULL) \ - Py_DECREF(_py_xdecref_tmp); \ - } while (0) - -#ifndef Py_LIMITED_API -/* Safely decref `op` and set `op` to `op2`. - * - * As in case of Py_CLEAR "the obvious" code can be deadly: - * - * Py_DECREF(op); - * op = op2; - * - * The safe way is: - * - * Py_SETREF(op, op2); - * - * That arranges to set `op` to `op2` _before_ decref'ing, so that any code - * triggered as a side-effect of `op` getting torn down no longer believes - * `op` points to a valid object. - * - * Py_XSETREF is a variant of Py_SETREF that uses Py_XDECREF instead of - * Py_DECREF. - */ - -#define Py_SETREF(op, op2) \ - do { \ - PyObject *_py_tmp = (PyObject *)(op); \ - (op) = (op2); \ - Py_DECREF(_py_tmp); \ - } while (0) - -#define Py_XSETREF(op, op2) \ - do { \ - PyObject *_py_tmp = (PyObject *)(op); \ - (op) = (op2); \ - Py_XDECREF(_py_tmp); \ - } while (0) - -#endif /* ifndef Py_LIMITED_API */ - -/* -These are provided as conveniences to Python runtime embedders, so that -they can have object code that is not dependent on Python compilation flags. -*/ -PyAPI_FUNC(void) Py_IncRef(PyObject *); -PyAPI_FUNC(void) Py_DecRef(PyObject *); - -PyAPI_DATA(PyTypeObject) _PyNone_Type; -PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type; - -/* -_Py_NoneStruct is an object of undefined type which can be used in contexts -where NULL (nil) is not suitable (since NULL often means 'error'). - -Don't forget to apply Py_INCREF() when returning this value!!! -*/ -PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ -#define Py_None (&_Py_NoneStruct) - -/* Macro for returning Py_None from a function */ -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None - -/* -Py_NotImplemented is a singleton used to signal that an operation is -not implemented for a given type combination. -*/ -PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ -#define Py_NotImplemented (&_Py_NotImplementedStruct) - -/* Macro for returning Py_NotImplemented from a function */ -#define Py_RETURN_NOTIMPLEMENTED \ - return Py_INCREF(Py_NotImplemented), Py_NotImplemented - -/* Rich comparison opcodes */ -#define Py_LT 0 -#define Py_LE 1 -#define Py_EQ 2 -#define Py_NE 3 -#define Py_GT 4 -#define Py_GE 5 - -/* Maps Py_LT to Py_GT, ..., Py_GE to Py_LE. - * Defined in object.c. - */ -PyAPI_DATA(int) _Py_SwappedOp[]; - - -/* -More conventions -================ - -Argument Checking ------------------ - -Functions that take objects as arguments normally don't check for nil -arguments, but they do check the type of the argument, and return an -error if the function doesn't apply to the type. - -Failure Modes -------------- - -Functions may fail for a variety of reasons, including running out of -memory. This is communicated to the caller in two ways: an error string -is set (see errors.h), and the function result differs: functions that -normally return a pointer return NULL for failure, functions returning -an integer return -1 (which could be a legal return value too!), and -other functions return 0 for success and -1 for failure. -Callers should always check for errors before using the result. If -an error was set, the caller must either explicitly clear it, or pass -the error on to its caller. - -Reference Counts ----------------- - -It takes a while to get used to the proper usage of reference counts. - -Functions that create an object set the reference count to 1; such new -objects must be stored somewhere or destroyed again with Py_DECREF(). -Some functions that 'store' objects, such as PyTuple_SetItem() and -PyList_SetItem(), -don't increment the reference count of the object, since the most -frequent use is to store a fresh object. Functions that 'retrieve' -objects, such as PyTuple_GetItem() and PyDict_GetItemString(), also -don't increment -the reference count, since most frequently the object is only looked at -quickly. Thus, to retrieve an object and store it again, the caller -must call Py_INCREF() explicitly. - -NOTE: functions that 'consume' a reference count, like -PyList_SetItem(), consume the reference even if the object wasn't -successfully stored, to simplify error handling. - -It seems attractive to make other functions that take an object as -argument consume a reference count; however, this may quickly get -confusing (even the current practice is already confusing). Consider -it carefully, it may save lots of calls to Py_INCREF() and Py_DECREF() at -times. -*/ - - -/* Trashcan mechanism, thanks to Christian Tismer. - -When deallocating a container object, it's possible to trigger an unbounded -chain of deallocations, as each Py_DECREF in turn drops the refcount on "the -next" object in the chain to 0. This can easily lead to stack faults, and -especially in threads (which typically have less stack space to work with). - -A container object that participates in cyclic gc can avoid this by -bracketing the body of its tp_dealloc function with a pair of macros: - -static void -mytype_dealloc(mytype *p) -{ - ... declarations go here ... - - PyObject_GC_UnTrack(p); // must untrack first - Py_TRASHCAN_SAFE_BEGIN(p) - ... The body of the deallocator goes here, including all calls ... - ... to Py_DECREF on contained objects. ... - Py_TRASHCAN_SAFE_END(p) -} - -CAUTION: Never return from the middle of the body! If the body needs to -"get out early", put a label immediately before the Py_TRASHCAN_SAFE_END -call, and goto it. Else the call-depth counter (see below) will stay -above 0 forever, and the trashcan will never get emptied. - -How it works: The BEGIN macro increments a call-depth counter. So long -as this counter is small, the body of the deallocator is run directly without -further ado. But if the counter gets large, it instead adds p to a list of -objects to be deallocated later, skips the body of the deallocator, and -resumes execution after the END macro. The tp_dealloc routine then returns -without deallocating anything (and so unbounded call-stack depth is avoided). - -When the call stack finishes unwinding again, code generated by the END macro -notices this, and calls another routine to deallocate all the objects that -may have been added to the list of deferred deallocations. In effect, a -chain of N deallocations is broken into N / PyTrash_UNWIND_LEVEL pieces, -with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL. -*/ - -/* This is the old private API, invoked by the macros before 3.2.4. - Kept for binary compatibility of extensions using the stable ABI. */ -PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*); -PyAPI_FUNC(void) _PyTrash_destroy_chain(void); -PyAPI_DATA(int) _PyTrash_delete_nesting; -PyAPI_DATA(PyObject *) _PyTrash_delete_later; - -/* The new thread-safe private API, invoked by the macros below. */ -PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*); -PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void); - -#define PyTrash_UNWIND_LEVEL 50 - -#define Py_TRASHCAN_SAFE_BEGIN(op) \ - do { \ - PyThreadState *_tstate = PyThreadState_GET(); \ - if (_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL) { \ - ++_tstate->trash_delete_nesting; - /* The body of the deallocator is here. */ -#define Py_TRASHCAN_SAFE_END(op) \ - --_tstate->trash_delete_nesting; \ - if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \ - _PyTrash_thread_destroy_chain(); \ - } \ - else \ - _PyTrash_thread_deposit_object((PyObject*)op); \ - } while (0); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) -_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks, - size_t sizeof_block); -PyAPI_FUNC(void) -_PyObject_DebugTypeStats(FILE *out); -#endif /* ifndef Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OBJECT_H */ +#ifndef Py_OBJECT_H +#define Py_OBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Object and type object interface */ + +/* +Objects are structures allocated on the heap. Special rules apply to +the use of objects to ensure they are properly garbage-collected. +Objects are never allocated statically or on the stack; they must be +accessed through special macros and functions only. (Type objects are +exceptions to the first rule; the standard types are represented by +statically initialized type objects, although work on type/class unification +for Python 2.2 made it possible to have heap-allocated type objects too). + +An object has a 'reference count' that is increased or decreased when a +pointer to the object is copied or deleted; when the reference count +reaches zero there are no references to the object left and it can be +removed from the heap. + +An object has a 'type' that determines what it represents and what kind +of data it contains. An object's type is fixed when it is created. +Types themselves are represented as objects; an object contains a +pointer to the corresponding type object. The type itself has a type +pointer pointing to the object representing the type 'type', which +contains a pointer to itself!). + +Objects do not float around in memory; once allocated an object keeps +the same size and address. Objects that must hold variable-size data +can contain pointers to variable-size parts of the object. Not all +objects of the same type have the same size; but the size cannot change +after allocation. (These restrictions are made so a reference to an +object can be simply a pointer -- moving an object would require +updating all the pointers, and changing an object's size would require +moving it if there was another object right next to it.) + +Objects are always accessed through pointers of the type 'PyObject *'. +The type 'PyObject' is a structure that only contains the reference count +and the type pointer. The actual memory allocated for an object +contains other data that can only be accessed after casting the pointer +to a pointer to a longer structure type. This longer type must start +with the reference count and type fields; the macro PyObject_HEAD should be +used for this (to accommodate for future changes). The implementation +of a particular object type can cast the object pointer to the proper +type and back. + +A standard interface exists for objects that contain an array of items +whose size is determined when the object is allocated. +*/ + +/* Py_DEBUG implies Py_TRACE_REFS. */ +#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS) +#define Py_TRACE_REFS +#endif + +/* Py_TRACE_REFS implies Py_REF_DEBUG. */ +#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) +#define Py_REF_DEBUG +#endif + +#if defined(Py_LIMITED_API) && defined(Py_REF_DEBUG) +#error Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG +#endif + + +#ifdef Py_TRACE_REFS +/* Define pointers to support a doubly-linked list of all live heap objects. */ +#define _PyObject_HEAD_EXTRA \ + struct _object *_ob_next; \ + struct _object *_ob_prev; + +#define _PyObject_EXTRA_INIT 0, 0, + +#else +#define _PyObject_HEAD_EXTRA +#define _PyObject_EXTRA_INIT +#endif + +/* PyObject_HEAD defines the initial segment of every PyObject. */ +#define PyObject_HEAD PyObject ob_base; + +#define PyObject_HEAD_INIT(type) \ + { _PyObject_EXTRA_INIT \ + 1, type }, + +#define PyVarObject_HEAD_INIT(type, size) \ + { PyObject_HEAD_INIT(type) size }, + +/* PyObject_VAR_HEAD defines the initial segment of all variable-size + * container objects. These end with a declaration of an array with 1 + * element, but enough space is malloc'ed so that the array actually + * has room for ob_size elements. Note that ob_size is an element count, + * not necessarily a byte count. + */ +#define PyObject_VAR_HEAD PyVarObject ob_base; +#define Py_INVALID_SIZE (Py_ssize_t)-1 + +/* Nothing is actually declared to be a PyObject, but every pointer to + * a Python object can be cast to a PyObject*. This is inheritance built + * by hand. Similarly every pointer to a variable-size Python object can, + * in addition, be cast to PyVarObject*. + */ +typedef struct _object { + _PyObject_HEAD_EXTRA + Py_ssize_t ob_refcnt; + struct _typeobject *ob_type; +} PyObject; + +typedef struct { + PyObject ob_base; + Py_ssize_t ob_size; /* Number of items in variable part */ +} PyVarObject; + +#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) + +/********************* String Literals ****************************************/ +/* This structure helps managing static strings. The basic usage goes like this: + Instead of doing + + r = PyObject_CallMethod(o, "foo", "args", ...); + + do + + _Py_IDENTIFIER(foo); + ... + r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...); + + PyId_foo is a static variable, either on block level or file level. On first + usage, the string "foo" is interned, and the structures are linked. On interpreter + shutdown, all strings are released (through _PyUnicode_ClearStaticStrings). + + Alternatively, _Py_static_string allows choosing the variable name. + _PyUnicode_FromId returns a borrowed reference to the interned string. + _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*. +*/ +typedef struct _Py_Identifier { + struct _Py_Identifier *next; + const char* string; + PyObject *object; +} _Py_Identifier; + +#define _Py_static_string_init(value) { 0, value, 0 } +#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value) +#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname) + +/* +Type objects contain a string containing the type name (to help somewhat +in debugging), the allocation parameters (see PyObject_New() and +PyObject_NewVar()), +and methods for accessing objects of the type. Methods are optional, a +nil pointer meaning that particular kind of access is not available for +this type. The Py_DECREF() macro uses the tp_dealloc method without +checking for a nil pointer; it should always be implemented except if +the implementation can guarantee that the reference count will never +reach zero (e.g., for statically allocated type objects). + +NB: the methods for certain type groups are now contained in separate +method blocks. +*/ + +typedef PyObject * (*unaryfunc)(PyObject *); +typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); +typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); +typedef int (*inquiry)(PyObject *); +typedef Py_ssize_t (*lenfunc)(PyObject *); +typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); +typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); +typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); +typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); +typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); + +#ifndef Py_LIMITED_API +/* buffer interface */ +typedef struct bufferinfo { + void *buf; + PyObject *obj; /* owned reference */ + Py_ssize_t len; + Py_ssize_t itemsize; /* This is Py_ssize_t so it can be + pointed to by strides in simple case.*/ + int readonly; + int ndim; + char *format; + Py_ssize_t *shape; + Py_ssize_t *strides; + Py_ssize_t *suboffsets; + void *internal; +} Py_buffer; + +typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); +typedef void (*releasebufferproc)(PyObject *, Py_buffer *); + +/* Maximum number of dimensions */ +#define PyBUF_MAX_NDIM 64 + +/* Flags for getting buffers */ +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +/* we used to include an E, backwards compatible alias */ +#define PyBUF_WRITEABLE PyBUF_WRITABLE +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) +#define PyBUF_CONTIG_RO (PyBUF_ND) + +#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) +#define PyBUF_STRIDED_RO (PyBUF_STRIDES) + +#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) + +#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) + + +#define PyBUF_READ 0x100 +#define PyBUF_WRITE 0x200 + +/* End buffer interface */ +#endif /* Py_LIMITED_API */ + +typedef int (*objobjproc)(PyObject *, PyObject *); +typedef int (*visitproc)(PyObject *, void *); +typedef int (*traverseproc)(PyObject *, visitproc, void *); + +#ifndef Py_LIMITED_API +typedef struct { + /* Number implementations must check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + binaryfunc nb_matrix_multiply; + binaryfunc nb_inplace_matrix_multiply; +} PyNumberMethods; + +typedef struct { + lenfunc sq_length; + binaryfunc sq_concat; + ssizeargfunc sq_repeat; + ssizeargfunc sq_item; + void *was_sq_slice; + ssizeobjargproc sq_ass_item; + void *was_sq_ass_slice; + objobjproc sq_contains; + + binaryfunc sq_inplace_concat; + ssizeargfunc sq_inplace_repeat; +} PySequenceMethods; + +typedef struct { + lenfunc mp_length; + binaryfunc mp_subscript; + objobjargproc mp_ass_subscript; +} PyMappingMethods; + +typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; +} PyAsyncMethods; + +typedef struct { + getbufferproc bf_getbuffer; + releasebufferproc bf_releasebuffer; +} PyBufferProcs; +#endif /* Py_LIMITED_API */ + +typedef void (*freefunc)(void *); +typedef void (*destructor)(PyObject *); +#ifndef Py_LIMITED_API +/* We can't provide a full compile-time check that limited-API + users won't implement tp_print. However, not defining printfunc + and making tp_print of a different function pointer type + should at least cause a warning in most cases. */ +typedef int (*printfunc)(PyObject *, FILE *, int); +#endif +typedef PyObject *(*getattrfunc)(PyObject *, char *); +typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); +typedef int (*setattrfunc)(PyObject *, char *, PyObject *); +typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); +typedef PyObject *(*reprfunc)(PyObject *); +typedef Py_hash_t (*hashfunc)(PyObject *); +typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); +typedef PyObject *(*getiterfunc) (PyObject *); +typedef PyObject *(*iternextfunc) (PyObject *); +typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); +typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); +typedef int (*initproc)(PyObject *, PyObject *, PyObject *); +typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); +typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t); + +#ifdef Py_LIMITED_API +typedef struct _typeobject PyTypeObject; /* opaque */ +#else +typedef struct _typeobject { + PyObject_VAR_HEAD + const char *tp_name; /* For printing, in format "." */ + Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + destructor tp_dealloc; + printfunc tp_print; + getattrfunc tp_getattr; + setattrfunc tp_setattr; + PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) + or tp_reserved (Python 3) */ + reprfunc tp_repr; + + /* Method suites for standard classes */ + + PyNumberMethods *tp_as_number; + PySequenceMethods *tp_as_sequence; + PyMappingMethods *tp_as_mapping; + + /* More standard operations (here for binary compatibility) */ + + hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + getattrofunc tp_getattro; + setattrofunc tp_setattro; + + /* Functions to access object as input/output buffer */ + PyBufferProcs *tp_as_buffer; + + /* Flags to define presence of optional/expanded features */ + unsigned long tp_flags; + + const char *tp_doc; /* Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + traverseproc tp_traverse; + + /* delete references to contained objects */ + inquiry tp_clear; + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + richcmpfunc tp_richcompare; + + /* weak reference enabler */ + Py_ssize_t tp_weaklistoffset; + + /* Iterators */ + getiterfunc tp_iter; + iternextfunc tp_iternext; + + /* Attribute descriptor and subclassing stuff */ + struct PyMethodDef *tp_methods; + struct PyMemberDef *tp_members; + struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + descrsetfunc tp_descr_set; + Py_ssize_t tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; /* Low-level free-memory routine */ + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + PyObject *tp_cache; + PyObject *tp_subclasses; + PyObject *tp_weaklist; + destructor tp_del; + + /* Type attribute cache version tag. Added in version 2.6 */ + unsigned int tp_version_tag; + + destructor tp_finalize; + +#ifdef COUNT_ALLOCS + /* these must be last and never explicitly initialized */ + Py_ssize_t tp_allocs; + Py_ssize_t tp_frees; + Py_ssize_t tp_maxalloc; + struct _typeobject *tp_prev; + struct _typeobject *tp_next; +#endif +} PyTypeObject; +#endif + +typedef struct{ + int slot; /* slot id, see below */ + void *pfunc; /* function pointer */ +} PyType_Slot; + +typedef struct{ + const char* name; + int basicsize; + int itemsize; + unsigned int flags; + PyType_Slot *slots; /* terminated by slot==0. */ +} PyType_Spec; + +PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 +PyAPI_FUNC(void*) PyType_GetSlot(PyTypeObject*, int); +#endif + +#ifndef Py_LIMITED_API +/* The *real* layout of a type object when allocated on the heap */ +typedef struct _heaptypeobject { + /* Note: there's a dependency on the order of these members + in slotptr() in typeobject.c . */ + PyTypeObject ht_type; + PyAsyncMethods as_async; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, + so that the mapping wins when both + the mapping and the sequence define + a given operator (e.g. __getitem__). + see add_operators() in typeobject.c . */ + PyBufferProcs as_buffer; + PyObject *ht_name, *ht_slots, *ht_qualname; + struct _dictkeysobject *ht_cached_keys; + /* here are optional user slots, followed by the members. */ +} PyHeapTypeObject; + +/* access macro to the members which are floating "behind" the object */ +#define PyHeapType_GET_MEMBERS(etype) \ + ((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize)) +#endif + +/* Generic type check */ +PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *); +#define PyObject_TypeCheck(ob, tp) \ + (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp))) + +PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ +PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ +PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ + +PyAPI_FUNC(unsigned long) PyType_GetFlags(PyTypeObject*); + +#define PyType_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS) +#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type) + +PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); +PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *, + PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *); +PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *); +PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *); +#endif +PyAPI_FUNC(unsigned int) PyType_ClearCache(void); +PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); +PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); +#endif + +/* Generic operations on objects */ +struct _Py_Identifier; +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); +PyAPI_FUNC(void) _Py_BreakPoint(void); +PyAPI_FUNC(void) _PyObject_Dump(PyObject *); +#endif +PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_Bytes(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); +PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); +PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *); +PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); +PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); +PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); +PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *); +PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *); +PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *); +PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); +#endif +PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *); +#endif +PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, + PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *); +PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *); +PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *); +PyAPI_FUNC(int) PyObject_IsTrue(PyObject *); +PyAPI_FUNC(int) PyObject_Not(PyObject *); +PyAPI_FUNC(int) PyCallable_Check(PyObject *); + +PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); +PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); +#endif + +/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes + dict as the last parameter. */ +PyAPI_FUNC(PyObject *) +_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(int) +_PyObject_GenericSetAttrWithDict(PyObject *, PyObject *, + PyObject *, PyObject *); + +/* Helper to look up a builtin object */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) +_PyObject_GetBuiltin(const char *name); +#endif + +/* PyObject_Dir(obj) acts like Python builtins.dir(obj), returning a + list of strings. PyObject_Dir(NULL) is like builtins.dir(), + returning the names of the current locals. In this case, if there are + no current locals, NULL is returned, and PyErr_Occurred() is false. +*/ +PyAPI_FUNC(PyObject *) PyObject_Dir(PyObject *); + + +/* Helpers for printing recursive container types */ +PyAPI_FUNC(int) Py_ReprEnter(PyObject *); +PyAPI_FUNC(void) Py_ReprLeave(PyObject *); + +/* Flag bits for printing: */ +#define Py_PRINT_RAW 1 /* No string quotes etc. */ + +/* +`Type flags (tp_flags) + +These flags are used to extend the type structure in a backwards-compatible +fashion. Extensions can use the flags to indicate (and test) when a given +type structure contains a new feature. The Python core will use these when +introducing new functionality between major revisions (to avoid mid-version +changes in the PYTHON_API_VERSION). + +Arbitration of the flag bit positions will need to be coordinated among +all extension writers who publically release their extensions (this will +be fewer than you might expect!).. + +Most flags were removed as of Python 3.0 to make room for new flags. (Some +flags are not for backwards compatibility but to indicate the presence of an +optional feature; these flags remain of course.) + +Type definitions should use Py_TPFLAGS_DEFAULT for their tp_flags value. + +Code can use PyType_HasFeature(type_ob, flag_value) to test whether the +given type object has a specified feature. +*/ + +/* Set if the type object is dynamically allocated */ +#define Py_TPFLAGS_HEAPTYPE (1UL << 9) + +/* Set if the type allows subclassing */ +#define Py_TPFLAGS_BASETYPE (1UL << 10) + +/* Set if the type is 'ready' -- fully initialized */ +#define Py_TPFLAGS_READY (1UL << 12) + +/* Set while the type is being 'readied', to prevent recursive ready calls */ +#define Py_TPFLAGS_READYING (1UL << 13) + +/* Objects support garbage collection (see objimp.h) */ +#define Py_TPFLAGS_HAVE_GC (1UL << 14) + +/* These two bits are preserved for Stackless Python, next after this is 17 */ +#ifdef STACKLESS +#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3UL << 15) +#else +#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0 +#endif + +/* Objects support type attribute cache */ +#define Py_TPFLAGS_HAVE_VERSION_TAG (1UL << 18) +#define Py_TPFLAGS_VALID_VERSION_TAG (1UL << 19) + +/* Type is abstract and cannot be instantiated */ +#define Py_TPFLAGS_IS_ABSTRACT (1UL << 20) + +/* These flags are used to determine if a type is a subclass. */ +#define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24) +#define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25) +#define Py_TPFLAGS_TUPLE_SUBCLASS (1UL << 26) +#define Py_TPFLAGS_BYTES_SUBCLASS (1UL << 27) +#define Py_TPFLAGS_UNICODE_SUBCLASS (1UL << 28) +#define Py_TPFLAGS_DICT_SUBCLASS (1UL << 29) +#define Py_TPFLAGS_BASE_EXC_SUBCLASS (1UL << 30) +#define Py_TPFLAGS_TYPE_SUBCLASS (1UL << 31) + +#define Py_TPFLAGS_DEFAULT ( \ + Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ + Py_TPFLAGS_HAVE_VERSION_TAG | \ + 0) + +/* NOTE: The following flags reuse lower bits (removed as part of the + * Python 3.0 transition). */ + +/* Type structure has tp_finalize member (3.4) */ +#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 0) + +#ifdef Py_LIMITED_API +#define PyType_HasFeature(t,f) ((PyType_GetFlags(t) & (f)) != 0) +#else +#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) +#endif +#define PyType_FastSubclass(t,f) PyType_HasFeature(t,f) + + +/* +The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement +reference counts. Py_DECREF calls the object's deallocator function when +the refcount falls to 0; for +objects that don't contain references to other objects or heap memory +this can be the standard function free(). Both macros can be used +wherever a void expression is allowed. The argument must not be a +NULL pointer. If it may be NULL, use Py_XINCREF/Py_XDECREF instead. +The macro _Py_NewReference(op) initialize reference counts to 1, and +in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional +bookkeeping appropriate to the special build. + +We assume that the reference count field can never overflow; this can +be proven when the size of the field is the same as the pointer size, so +we ignore the possibility. Provided a C int is at least 32 bits (which +is implicitly assumed in many parts of this code), that's enough for +about 2**31 references to an object. + +XXX The following became out of date in Python 2.2, but I'm not sure +XXX what the full truth is now. Certainly, heap-allocated type objects +XXX can and should be deallocated. +Type objects should never be deallocated; the type pointer in an object +is not considered to be a reference to the type object, to save +complications in the deallocation function. (This is actually a +decision that's up to the implementer of each new type so if you want, +you can count such references to the type object.) +*/ + +/* First define a pile of simple helper macros, one set per special + * build symbol. These either expand to the obvious things, or to + * nothing at all when the special mode isn't in effect. The main + * macros can later be defined just once then, yet expand to different + * things depending on which special build options are and aren't in effect. + * Trust me : while painful, this is 20x easier to understand than, + * e.g, defining _Py_NewReference five different times in a maze of nested + * #ifdefs (we used to do that -- it was impenetrable). + */ +#ifdef Py_REF_DEBUG +PyAPI_DATA(Py_ssize_t) _Py_RefTotal; +PyAPI_FUNC(void) _Py_NegativeRefcount(const char *fname, + int lineno, PyObject *op); +PyAPI_FUNC(PyObject *) _PyDict_Dummy(void); +PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +#define _Py_INC_REFTOTAL _Py_RefTotal++ +#define _Py_DEC_REFTOTAL _Py_RefTotal-- +#define _Py_REF_DEBUG_COMMA , +#define _Py_CHECK_REFCNT(OP) \ +{ if (((PyObject*)OP)->ob_refcnt < 0) \ + _Py_NegativeRefcount(__FILE__, __LINE__, \ + (PyObject *)(OP)); \ +} +/* Py_REF_DEBUG also controls the display of refcounts and memory block + * allocations at the interactive prompt and at interpreter shutdown + */ +PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); +#define _PY_DEBUG_PRINT_TOTAL_REFS() _PyDebug_PrintTotalRefs() +#else +#define _Py_INC_REFTOTAL +#define _Py_DEC_REFTOTAL +#define _Py_REF_DEBUG_COMMA +#define _Py_CHECK_REFCNT(OP) /* a semicolon */; +#define _PY_DEBUG_PRINT_TOTAL_REFS() +#endif /* Py_REF_DEBUG */ + +#ifdef COUNT_ALLOCS +PyAPI_FUNC(void) inc_count(PyTypeObject *); +PyAPI_FUNC(void) dec_count(PyTypeObject *); +#define _Py_INC_TPALLOCS(OP) inc_count(Py_TYPE(OP)) +#define _Py_INC_TPFREES(OP) dec_count(Py_TYPE(OP)) +#define _Py_DEC_TPFREES(OP) Py_TYPE(OP)->tp_frees-- +#define _Py_COUNT_ALLOCS_COMMA , +#else +#define _Py_INC_TPALLOCS(OP) +#define _Py_INC_TPFREES(OP) +#define _Py_DEC_TPFREES(OP) +#define _Py_COUNT_ALLOCS_COMMA +#endif /* COUNT_ALLOCS */ + +#ifdef Py_TRACE_REFS +/* Py_TRACE_REFS is such major surgery that we call external routines. */ +PyAPI_FUNC(void) _Py_NewReference(PyObject *); +PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); +PyAPI_FUNC(void) _Py_Dealloc(PyObject *); +PyAPI_FUNC(void) _Py_PrintReferences(FILE *); +PyAPI_FUNC(void) _Py_PrintReferenceAddresses(FILE *); +PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); + +#else +/* Without Py_TRACE_REFS, there's little enough to do that we expand code + * inline. + */ +#define _Py_NewReference(op) ( \ + _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + Py_REFCNT(op) = 1) + +#define _Py_ForgetReference(op) _Py_INC_TPFREES(op) + +#ifdef Py_LIMITED_API +PyAPI_FUNC(void) _Py_Dealloc(PyObject *); +#else +#define _Py_Dealloc(op) ( \ + _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \ + (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op))) +#endif +#endif /* !Py_TRACE_REFS */ + +#define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + ((PyObject *)(op))->ob_refcnt++) + +#define Py_DECREF(op) \ + do { \ + PyObject *_py_decref_tmp = (PyObject *)(op); \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --(_py_decref_tmp)->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(_py_decref_tmp) \ + else \ + _Py_Dealloc(_py_decref_tmp); \ + } while (0) + +/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear + * and tp_dealloc implementations. + * + * Note that "the obvious" code can be deadly: + * + * Py_XDECREF(op); + * op = NULL; + * + * Typically, `op` is something like self->containee, and `self` is done + * using its `containee` member. In the code sequence above, suppose + * `containee` is non-NULL with a refcount of 1. Its refcount falls to + * 0 on the first line, which can trigger an arbitrary amount of code, + * possibly including finalizers (like __del__ methods or weakref callbacks) + * coded in Python, which in turn can release the GIL and allow other threads + * to run, etc. Such code may even invoke methods of `self` again, or cause + * cyclic gc to trigger, but-- oops! --self->containee still points to the + * object being torn down, and it may be in an insane state while being torn + * down. This has in fact been a rich historic source of miserable (rare & + * hard-to-diagnose) segfaulting (and other) bugs. + * + * The safe way is: + * + * Py_CLEAR(op); + * + * That arranges to set `op` to NULL _before_ decref'ing, so that any code + * triggered as a side-effect of `op` getting torn down no longer believes + * `op` points to a valid object. + * + * There are cases where it's safe to use the naive code, but they're brittle. + * For example, if `op` points to a Python integer, you know that destroying + * one of those can't cause problems -- but in part that relies on that + * Python integers aren't currently weakly referencable. Best practice is + * to use Py_CLEAR() even if you can't think of a reason for why you need to. + */ +#define Py_CLEAR(op) \ + do { \ + PyObject *_py_tmp = (PyObject *)(op); \ + if (_py_tmp != NULL) { \ + (op) = NULL; \ + Py_DECREF(_py_tmp); \ + } \ + } while (0) + +/* Macros to use in case the object pointer may be NULL: */ +#define Py_XINCREF(op) \ + do { \ + PyObject *_py_xincref_tmp = (PyObject *)(op); \ + if (_py_xincref_tmp != NULL) \ + Py_INCREF(_py_xincref_tmp); \ + } while (0) + +#define Py_XDECREF(op) \ + do { \ + PyObject *_py_xdecref_tmp = (PyObject *)(op); \ + if (_py_xdecref_tmp != NULL) \ + Py_DECREF(_py_xdecref_tmp); \ + } while (0) + +#ifndef Py_LIMITED_API +/* Safely decref `op` and set `op` to `op2`. + * + * As in case of Py_CLEAR "the obvious" code can be deadly: + * + * Py_DECREF(op); + * op = op2; + * + * The safe way is: + * + * Py_SETREF(op, op2); + * + * That arranges to set `op` to `op2` _before_ decref'ing, so that any code + * triggered as a side-effect of `op` getting torn down no longer believes + * `op` points to a valid object. + * + * Py_XSETREF is a variant of Py_SETREF that uses Py_XDECREF instead of + * Py_DECREF. + */ + +#define Py_SETREF(op, op2) \ + do { \ + PyObject *_py_tmp = (PyObject *)(op); \ + (op) = (op2); \ + Py_DECREF(_py_tmp); \ + } while (0) + +#define Py_XSETREF(op, op2) \ + do { \ + PyObject *_py_tmp = (PyObject *)(op); \ + (op) = (op2); \ + Py_XDECREF(_py_tmp); \ + } while (0) + +#endif /* ifndef Py_LIMITED_API */ + +/* +These are provided as conveniences to Python runtime embedders, so that +they can have object code that is not dependent on Python compilation flags. +*/ +PyAPI_FUNC(void) Py_IncRef(PyObject *); +PyAPI_FUNC(void) Py_DecRef(PyObject *); + +PyAPI_DATA(PyTypeObject) _PyNone_Type; +PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type; + +/* +_Py_NoneStruct is an object of undefined type which can be used in contexts +where NULL (nil) is not suitable (since NULL often means 'error'). + +Don't forget to apply Py_INCREF() when returning this value!!! +*/ +PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ +#define Py_None (&_Py_NoneStruct) + +/* Macro for returning Py_None from a function */ +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None + +/* +Py_NotImplemented is a singleton used to signal that an operation is +not implemented for a given type combination. +*/ +PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ +#define Py_NotImplemented (&_Py_NotImplementedStruct) + +/* Macro for returning Py_NotImplemented from a function */ +#define Py_RETURN_NOTIMPLEMENTED \ + return Py_INCREF(Py_NotImplemented), Py_NotImplemented + +/* Rich comparison opcodes */ +#define Py_LT 0 +#define Py_LE 1 +#define Py_EQ 2 +#define Py_NE 3 +#define Py_GT 4 +#define Py_GE 5 + +/* Maps Py_LT to Py_GT, ..., Py_GE to Py_LE. + * Defined in object.c. + */ +PyAPI_DATA(int) _Py_SwappedOp[]; + + +/* +More conventions +================ + +Argument Checking +----------------- + +Functions that take objects as arguments normally don't check for nil +arguments, but they do check the type of the argument, and return an +error if the function doesn't apply to the type. + +Failure Modes +------------- + +Functions may fail for a variety of reasons, including running out of +memory. This is communicated to the caller in two ways: an error string +is set (see errors.h), and the function result differs: functions that +normally return a pointer return NULL for failure, functions returning +an integer return -1 (which could be a legal return value too!), and +other functions return 0 for success and -1 for failure. +Callers should always check for errors before using the result. If +an error was set, the caller must either explicitly clear it, or pass +the error on to its caller. + +Reference Counts +---------------- + +It takes a while to get used to the proper usage of reference counts. + +Functions that create an object set the reference count to 1; such new +objects must be stored somewhere or destroyed again with Py_DECREF(). +Some functions that 'store' objects, such as PyTuple_SetItem() and +PyList_SetItem(), +don't increment the reference count of the object, since the most +frequent use is to store a fresh object. Functions that 'retrieve' +objects, such as PyTuple_GetItem() and PyDict_GetItemString(), also +don't increment +the reference count, since most frequently the object is only looked at +quickly. Thus, to retrieve an object and store it again, the caller +must call Py_INCREF() explicitly. + +NOTE: functions that 'consume' a reference count, like +PyList_SetItem(), consume the reference even if the object wasn't +successfully stored, to simplify error handling. + +It seems attractive to make other functions that take an object as +argument consume a reference count; however, this may quickly get +confusing (even the current practice is already confusing). Consider +it carefully, it may save lots of calls to Py_INCREF() and Py_DECREF() at +times. +*/ + + +/* Trashcan mechanism, thanks to Christian Tismer. + +When deallocating a container object, it's possible to trigger an unbounded +chain of deallocations, as each Py_DECREF in turn drops the refcount on "the +next" object in the chain to 0. This can easily lead to stack faults, and +especially in threads (which typically have less stack space to work with). + +A container object that participates in cyclic gc can avoid this by +bracketing the body of its tp_dealloc function with a pair of macros: + +static void +mytype_dealloc(mytype *p) +{ + ... declarations go here ... + + PyObject_GC_UnTrack(p); // must untrack first + Py_TRASHCAN_SAFE_BEGIN(p) + ... The body of the deallocator goes here, including all calls ... + ... to Py_DECREF on contained objects. ... + Py_TRASHCAN_SAFE_END(p) +} + +CAUTION: Never return from the middle of the body! If the body needs to +"get out early", put a label immediately before the Py_TRASHCAN_SAFE_END +call, and goto it. Else the call-depth counter (see below) will stay +above 0 forever, and the trashcan will never get emptied. + +How it works: The BEGIN macro increments a call-depth counter. So long +as this counter is small, the body of the deallocator is run directly without +further ado. But if the counter gets large, it instead adds p to a list of +objects to be deallocated later, skips the body of the deallocator, and +resumes execution after the END macro. The tp_dealloc routine then returns +without deallocating anything (and so unbounded call-stack depth is avoided). + +When the call stack finishes unwinding again, code generated by the END macro +notices this, and calls another routine to deallocate all the objects that +may have been added to the list of deferred deallocations. In effect, a +chain of N deallocations is broken into N / PyTrash_UNWIND_LEVEL pieces, +with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL. +*/ + +/* This is the old private API, invoked by the macros before 3.2.4. + Kept for binary compatibility of extensions using the stable ABI. */ +PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*); +PyAPI_FUNC(void) _PyTrash_destroy_chain(void); +PyAPI_DATA(int) _PyTrash_delete_nesting; +PyAPI_DATA(PyObject *) _PyTrash_delete_later; + +/* The new thread-safe private API, invoked by the macros below. */ +PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*); +PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void); + +#define PyTrash_UNWIND_LEVEL 50 + +#define Py_TRASHCAN_SAFE_BEGIN(op) \ + do { \ + PyThreadState *_tstate = PyThreadState_GET(); \ + if (_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL) { \ + ++_tstate->trash_delete_nesting; + /* The body of the deallocator is here. */ +#define Py_TRASHCAN_SAFE_END(op) \ + --_tstate->trash_delete_nesting; \ + if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \ + _PyTrash_thread_destroy_chain(); \ + } \ + else \ + _PyTrash_thread_deposit_object((PyObject*)op); \ + } while (0); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) +_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks, + size_t sizeof_block); +PyAPI_FUNC(void) +_PyObject_DebugTypeStats(FILE *out); +#endif /* ifndef Py_LIMITED_API */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OBJECT_H */ diff --git a/libs/nxpy/include/objimpl.h b/libs/nxpy/include/objimpl.h index 65b6d91c..03affd7f 100644 --- a/libs/nxpy/include/objimpl.h +++ b/libs/nxpy/include/objimpl.h @@ -1,363 +1,363 @@ -/* The PyObject_ memory family: high-level object memory interfaces. - See pymem.h for the low-level PyMem_ family. -*/ - -#ifndef Py_OBJIMPL_H -#define Py_OBJIMPL_H - -#include "pymem.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* BEWARE: - - Each interface exports both functions and macros. Extension modules should - use the functions, to ensure binary compatibility across Python versions. - Because the Python implementation is free to change internal details, and - the macros may (or may not) expose details for speed, if you do use the - macros you must recompile your extensions with each Python release. - - Never mix calls to PyObject_ memory functions with calls to the platform - malloc/realloc/ calloc/free, or with calls to PyMem_. -*/ - -/* -Functions and macros for modules that implement new object types. - - - PyObject_New(type, typeobj) allocates memory for a new object of the given - type, and initializes part of it. 'type' must be the C structure type used - to represent the object, and 'typeobj' the address of the corresponding - type object. Reference count and type pointer are filled in; the rest of - the bytes of the object are *undefined*! The resulting expression type is - 'type *'. The size of the object is determined by the tp_basicsize field - of the type object. - - - PyObject_NewVar(type, typeobj, n) is similar but allocates a variable-size - object with room for n items. In addition to the refcount and type pointer - fields, this also fills in the ob_size field. - - - PyObject_Del(op) releases the memory allocated for an object. It does not - run a destructor -- it only frees the memory. PyObject_Free is identical. - - - PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) don't - allocate memory. Instead of a 'type' parameter, they take a pointer to a - new object (allocated by an arbitrary allocator), and initialize its object - header fields. - -Note that objects created with PyObject_{New, NewVar} are allocated using the -specialized Python allocator (implemented in obmalloc.c), if WITH_PYMALLOC is -enabled. In addition, a special debugging allocator is used if PYMALLOC_DEBUG -is also #defined. - -In case a specific form of memory management is needed (for example, if you -must use the platform malloc heap(s), or shared memory, or C++ local storage or -operator new), you must first allocate the object with your custom allocator, -then pass its pointer to PyObject_{Init, InitVar} for filling in its Python- -specific fields: reference count, type pointer, possibly others. You should -be aware that Python no control over these objects because they don't -cooperate with the Python memory manager. Such objects may not be eligible -for automatic garbage collection and you have to make sure that they are -released accordingly whenever their destructor gets called (cf. the specific -form of memory management you're using). - -Unless you have specific memory management requirements, use -PyObject_{New, NewVar, Del}. -*/ - -/* - * Raw object memory interface - * =========================== - */ - -/* Functions to call the same malloc/realloc/free as used by Python's - object allocator. If WITH_PYMALLOC is enabled, these may differ from - the platform malloc/realloc/free. The Python object allocator is - designed for fast, cache-conscious allocation of many "small" objects, - and with low hidden memory overhead. - - PyObject_Malloc(0) returns a unique non-NULL pointer if possible. - - PyObject_Realloc(NULL, n) acts like PyObject_Malloc(n). - PyObject_Realloc(p != NULL, 0) does not return NULL, or free the memory - at p. - - Returned pointers must be checked for NULL explicitly; no action is - performed on failure other than to return NULL (no warning it printed, no - exception is set, etc). - - For allocating objects, use PyObject_{New, NewVar} instead whenever - possible. The PyObject_{Malloc, Realloc, Free} family is exposed - so that you can exploit Python's small-block allocator for non-object - uses. If you must use these routines to allocate object memory, make sure - the object gets initialized via PyObject_{Init, InitVar} after obtaining - the raw memory. -*/ -PyAPI_FUNC(void *) PyObject_Malloc(size_t size); -PyAPI_FUNC(void *) PyObject_Calloc(size_t nelem, size_t elsize); -PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyObject_Free(void *ptr); - -/* This function returns the number of allocated memory blocks, regardless of size */ -PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); - -/* Macros */ -#ifdef WITH_PYMALLOC -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out); -#endif /* #ifndef Py_LIMITED_API */ -#endif - -/* Macros */ -#define PyObject_MALLOC PyObject_Malloc -#define PyObject_REALLOC PyObject_Realloc -#define PyObject_FREE PyObject_Free -#define PyObject_Del PyObject_Free -#define PyObject_DEL PyObject_Free - - -/* - * Generic object allocator interface - * ================================== - */ - -/* Functions */ -PyAPI_FUNC(PyObject *) PyObject_Init(PyObject *, PyTypeObject *); -PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *, - PyTypeObject *, Py_ssize_t); -PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *); -PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); - -#define PyObject_New(type, typeobj) \ - ( (type *) _PyObject_New(typeobj) ) -#define PyObject_NewVar(type, typeobj, n) \ - ( (type *) _PyObject_NewVar((typeobj), (n)) ) - -/* Macros trading binary compatibility for speed. See also pymem.h. - Note that these macros expect non-NULL object pointers.*/ -#define PyObject_INIT(op, typeobj) \ - ( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) -#define PyObject_INIT_VAR(op, typeobj, size) \ - ( Py_SIZE(op) = (size), PyObject_INIT((op), (typeobj)) ) - -#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) - -/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a - vrbl-size object with nitems items, exclusive of gc overhead (if any). The - value is rounded up to the closest multiple of sizeof(void *), in order to - ensure that pointer fields at the end of the object are correctly aligned - for the platform (this is of special importance for subclasses of, e.g., - str or int, so that pointers can be stored after the embedded data). - - Note that there's no memory wastage in doing this, as malloc has to - return (at worst) pointer-aligned memory anyway. -*/ -#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 -# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" -#endif - -#define _PyObject_VAR_SIZE(typeobj, nitems) \ - _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ - (nitems)*(typeobj)->tp_itemsize, \ - SIZEOF_VOID_P) - -#define PyObject_NEW(type, typeobj) \ -( (type *) PyObject_Init( \ - (PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) ) - -#define PyObject_NEW_VAR(type, typeobj, n) \ -( (type *) PyObject_InitVar( \ - (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\ - (typeobj), (n)) ) - -/* This example code implements an object constructor with a custom - allocator, where PyObject_New is inlined, and shows the important - distinction between two steps (at least): - 1) the actual allocation of the object storage; - 2) the initialization of the Python specific fields - in this storage with PyObject_{Init, InitVar}. - - PyObject * - YourObject_New(...) - { - PyObject *op; - - op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); - if (op == NULL) - return PyErr_NoMemory(); - - PyObject_Init(op, &YourTypeStruct); - - op->ob_field = value; - ... - return op; - } - - Note that in C++, the use of the new operator usually implies that - the 1st step is performed automatically for you, so in a C++ class - constructor you would start directly with PyObject_Init/InitVar -*/ - -#ifndef Py_LIMITED_API -typedef struct { - /* user context passed as the first argument to the 2 functions */ - void *ctx; - - /* allocate an arena of size bytes */ - void* (*alloc) (void *ctx, size_t size); - - /* free an arena */ - void (*free) (void *ctx, void *ptr, size_t size); -} PyObjectArenaAllocator; - -/* Get the arena allocator. */ -PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); - -/* Set the arena allocator. */ -PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); -#endif - - -/* - * Garbage Collection Support - * ========================== - */ - -/* C equivalent of gc.collect(). */ -PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); -#endif - -/* Test if a type has a GC head */ -#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) - -/* Test if an object has a GC head */ -#define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ - (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o))) - -PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t); -#define PyObject_GC_Resize(type, op, n) \ - ( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) ) - -/* GC information is stored BEFORE the object structure. */ -#ifndef Py_LIMITED_API -typedef union _gc_head { - struct { - union _gc_head *gc_next; - union _gc_head *gc_prev; - Py_ssize_t gc_refs; - } gc; - double dummy; /* force worst-case alignment */ -} PyGC_Head; - -extern PyGC_Head *_PyGC_generation0; - -#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1) - -/* Bit 0 is set when tp_finalize is called */ -#define _PyGC_REFS_MASK_FINALIZED (1 << 0) -/* The (N-1) most significant bits contain the gc state / refcount */ -#define _PyGC_REFS_SHIFT (1) -#define _PyGC_REFS_MASK (((size_t) -1) << _PyGC_REFS_SHIFT) - -#define _PyGCHead_REFS(g) ((g)->gc.gc_refs >> _PyGC_REFS_SHIFT) -#define _PyGCHead_SET_REFS(g, v) do { \ - (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK) \ - | (((size_t)(v)) << _PyGC_REFS_SHIFT); \ - } while (0) -#define _PyGCHead_DECREF(g) ((g)->gc.gc_refs -= 1 << _PyGC_REFS_SHIFT) - -#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_refs & _PyGC_REFS_MASK_FINALIZED) != 0) -#define _PyGCHead_SET_FINALIZED(g, v) do { \ - (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK_FINALIZED) \ - | (v != 0); \ - } while (0) - -#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o)) -#define _PyGC_SET_FINALIZED(o, v) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o), v) - -#define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o)) - -#define _PyGC_REFS_UNTRACKED (-2) -#define _PyGC_REFS_REACHABLE (-3) -#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4) - -/* Tell the GC to track this object. NB: While the object is tracked the - * collector it must be safe to call the ob_traverse method. */ -#define _PyObject_GC_TRACK(o) do { \ - PyGC_Head *g = _Py_AS_GC(o); \ - if (_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED) \ - Py_FatalError("GC object already tracked"); \ - _PyGCHead_SET_REFS(g, _PyGC_REFS_REACHABLE); \ - g->gc.gc_next = _PyGC_generation0; \ - g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \ - g->gc.gc_prev->gc.gc_next = g; \ - _PyGC_generation0->gc.gc_prev = g; \ - } while (0); - -/* Tell the GC to stop tracking this object. - * gc_next doesn't need to be set to NULL, but doing so is a good - * way to provoke memory errors if calling code is confused. - */ -#define _PyObject_GC_UNTRACK(o) do { \ - PyGC_Head *g = _Py_AS_GC(o); \ - assert(_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED); \ - _PyGCHead_SET_REFS(g, _PyGC_REFS_UNTRACKED); \ - g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \ - g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \ - g->gc.gc_next = NULL; \ - } while (0); - -/* True if the object is currently tracked by the GC. */ -#define _PyObject_GC_IS_TRACKED(o) \ - (_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED) - -/* True if the object may be tracked by the GC in the future, or already is. - This can be useful to implement some optimizations. */ -#define _PyObject_GC_MAY_BE_TRACKED(obj) \ - (PyObject_IS_GC(obj) && \ - (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj))) -#endif /* Py_LIMITED_API */ - -PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size); -PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size); -PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *); -PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t); -PyAPI_FUNC(void) PyObject_GC_Track(void *); -PyAPI_FUNC(void) PyObject_GC_UnTrack(void *); -PyAPI_FUNC(void) PyObject_GC_Del(void *); - -#define PyObject_GC_New(type, typeobj) \ - ( (type *) _PyObject_GC_New(typeobj) ) -#define PyObject_GC_NewVar(type, typeobj, n) \ - ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) - - -/* Utility macro to help write tp_traverse functions. - * To use this macro, the tp_traverse function must name its arguments - * "visit" and "arg". This is intended to keep tp_traverse functions - * looking as much alike as possible. - */ -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((PyObject *)(op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) - - -/* Test if a type supports weak references */ -#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0) - -#define PyObject_GET_WEAKREFS_LISTPTR(o) \ - ((PyObject **) (((char *) (o)) + Py_TYPE(o)->tp_weaklistoffset)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OBJIMPL_H */ +/* The PyObject_ memory family: high-level object memory interfaces. + See pymem.h for the low-level PyMem_ family. +*/ + +#ifndef Py_OBJIMPL_H +#define Py_OBJIMPL_H + +#include "pymem.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEWARE: + + Each interface exports both functions and macros. Extension modules should + use the functions, to ensure binary compatibility across Python versions. + Because the Python implementation is free to change internal details, and + the macros may (or may not) expose details for speed, if you do use the + macros you must recompile your extensions with each Python release. + + Never mix calls to PyObject_ memory functions with calls to the platform + malloc/realloc/ calloc/free, or with calls to PyMem_. +*/ + +/* +Functions and macros for modules that implement new object types. + + - PyObject_New(type, typeobj) allocates memory for a new object of the given + type, and initializes part of it. 'type' must be the C structure type used + to represent the object, and 'typeobj' the address of the corresponding + type object. Reference count and type pointer are filled in; the rest of + the bytes of the object are *undefined*! The resulting expression type is + 'type *'. The size of the object is determined by the tp_basicsize field + of the type object. + + - PyObject_NewVar(type, typeobj, n) is similar but allocates a variable-size + object with room for n items. In addition to the refcount and type pointer + fields, this also fills in the ob_size field. + + - PyObject_Del(op) releases the memory allocated for an object. It does not + run a destructor -- it only frees the memory. PyObject_Free is identical. + + - PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) don't + allocate memory. Instead of a 'type' parameter, they take a pointer to a + new object (allocated by an arbitrary allocator), and initialize its object + header fields. + +Note that objects created with PyObject_{New, NewVar} are allocated using the +specialized Python allocator (implemented in obmalloc.c), if WITH_PYMALLOC is +enabled. In addition, a special debugging allocator is used if PYMALLOC_DEBUG +is also #defined. + +In case a specific form of memory management is needed (for example, if you +must use the platform malloc heap(s), or shared memory, or C++ local storage or +operator new), you must first allocate the object with your custom allocator, +then pass its pointer to PyObject_{Init, InitVar} for filling in its Python- +specific fields: reference count, type pointer, possibly others. You should +be aware that Python no control over these objects because they don't +cooperate with the Python memory manager. Such objects may not be eligible +for automatic garbage collection and you have to make sure that they are +released accordingly whenever their destructor gets called (cf. the specific +form of memory management you're using). + +Unless you have specific memory management requirements, use +PyObject_{New, NewVar, Del}. +*/ + +/* + * Raw object memory interface + * =========================== + */ + +/* Functions to call the same malloc/realloc/free as used by Python's + object allocator. If WITH_PYMALLOC is enabled, these may differ from + the platform malloc/realloc/free. The Python object allocator is + designed for fast, cache-conscious allocation of many "small" objects, + and with low hidden memory overhead. + + PyObject_Malloc(0) returns a unique non-NULL pointer if possible. + + PyObject_Realloc(NULL, n) acts like PyObject_Malloc(n). + PyObject_Realloc(p != NULL, 0) does not return NULL, or free the memory + at p. + + Returned pointers must be checked for NULL explicitly; no action is + performed on failure other than to return NULL (no warning it printed, no + exception is set, etc). + + For allocating objects, use PyObject_{New, NewVar} instead whenever + possible. The PyObject_{Malloc, Realloc, Free} family is exposed + so that you can exploit Python's small-block allocator for non-object + uses. If you must use these routines to allocate object memory, make sure + the object gets initialized via PyObject_{Init, InitVar} after obtaining + the raw memory. +*/ +PyAPI_FUNC(void *) PyObject_Malloc(size_t size); +PyAPI_FUNC(void *) PyObject_Calloc(size_t nelem, size_t elsize); +PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyObject_Free(void *ptr); + +/* This function returns the number of allocated memory blocks, regardless of size */ +PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void); + +/* Macros */ +#ifdef WITH_PYMALLOC +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyObject_DebugMallocStats(FILE *out); +#endif /* #ifndef Py_LIMITED_API */ +#endif + +/* Macros */ +#define PyObject_MALLOC PyObject_Malloc +#define PyObject_REALLOC PyObject_Realloc +#define PyObject_FREE PyObject_Free +#define PyObject_Del PyObject_Free +#define PyObject_DEL PyObject_Free + + +/* + * Generic object allocator interface + * ================================== + */ + +/* Functions */ +PyAPI_FUNC(PyObject *) PyObject_Init(PyObject *, PyTypeObject *); +PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *, + PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *); +PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); + +#define PyObject_New(type, typeobj) \ + ( (type *) _PyObject_New(typeobj) ) +#define PyObject_NewVar(type, typeobj, n) \ + ( (type *) _PyObject_NewVar((typeobj), (n)) ) + +/* Macros trading binary compatibility for speed. See also pymem.h. + Note that these macros expect non-NULL object pointers.*/ +#define PyObject_INIT(op, typeobj) \ + ( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) +#define PyObject_INIT_VAR(op, typeobj, size) \ + ( Py_SIZE(op) = (size), PyObject_INIT((op), (typeobj)) ) + +#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) + +/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a + vrbl-size object with nitems items, exclusive of gc overhead (if any). The + value is rounded up to the closest multiple of sizeof(void *), in order to + ensure that pointer fields at the end of the object are correctly aligned + for the platform (this is of special importance for subclasses of, e.g., + str or int, so that pointers can be stored after the embedded data). + + Note that there's no memory wastage in doing this, as malloc has to + return (at worst) pointer-aligned memory anyway. +*/ +#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 +# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" +#endif + +#define _PyObject_VAR_SIZE(typeobj, nitems) \ + _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ + (nitems)*(typeobj)->tp_itemsize, \ + SIZEOF_VOID_P) + +#define PyObject_NEW(type, typeobj) \ +( (type *) PyObject_Init( \ + (PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) ) + +#define PyObject_NEW_VAR(type, typeobj, n) \ +( (type *) PyObject_InitVar( \ + (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\ + (typeobj), (n)) ) + +/* This example code implements an object constructor with a custom + allocator, where PyObject_New is inlined, and shows the important + distinction between two steps (at least): + 1) the actual allocation of the object storage; + 2) the initialization of the Python specific fields + in this storage with PyObject_{Init, InitVar}. + + PyObject * + YourObject_New(...) + { + PyObject *op; + + op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); + if (op == NULL) + return PyErr_NoMemory(); + + PyObject_Init(op, &YourTypeStruct); + + op->ob_field = value; + ... + return op; + } + + Note that in C++, the use of the new operator usually implies that + the 1st step is performed automatically for you, so in a C++ class + constructor you would start directly with PyObject_Init/InitVar +*/ + +#ifndef Py_LIMITED_API +typedef struct { + /* user context passed as the first argument to the 2 functions */ + void *ctx; + + /* allocate an arena of size bytes */ + void* (*alloc) (void *ctx, size_t size); + + /* free an arena */ + void (*free) (void *ctx, void *ptr, size_t size); +} PyObjectArenaAllocator; + +/* Get the arena allocator. */ +PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator); + +/* Set the arena allocator. */ +PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator); +#endif + + +/* + * Garbage Collection Support + * ========================== + */ + +/* C equivalent of gc.collect(). */ +PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); +#endif + +/* Test if a type has a GC head */ +#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) + +/* Test if an object has a GC head */ +#define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ + (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o))) + +PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t); +#define PyObject_GC_Resize(type, op, n) \ + ( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) ) + +/* GC information is stored BEFORE the object structure. */ +#ifndef Py_LIMITED_API +typedef union _gc_head { + struct { + union _gc_head *gc_next; + union _gc_head *gc_prev; + Py_ssize_t gc_refs; + } gc; + double dummy; /* force worst-case alignment */ +} PyGC_Head; + +extern PyGC_Head *_PyGC_generation0; + +#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1) + +/* Bit 0 is set when tp_finalize is called */ +#define _PyGC_REFS_MASK_FINALIZED (1 << 0) +/* The (N-1) most significant bits contain the gc state / refcount */ +#define _PyGC_REFS_SHIFT (1) +#define _PyGC_REFS_MASK (((size_t) -1) << _PyGC_REFS_SHIFT) + +#define _PyGCHead_REFS(g) ((g)->gc.gc_refs >> _PyGC_REFS_SHIFT) +#define _PyGCHead_SET_REFS(g, v) do { \ + (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK) \ + | (((size_t)(v)) << _PyGC_REFS_SHIFT); \ + } while (0) +#define _PyGCHead_DECREF(g) ((g)->gc.gc_refs -= 1 << _PyGC_REFS_SHIFT) + +#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_refs & _PyGC_REFS_MASK_FINALIZED) != 0) +#define _PyGCHead_SET_FINALIZED(g, v) do { \ + (g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK_FINALIZED) \ + | (v != 0); \ + } while (0) + +#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o)) +#define _PyGC_SET_FINALIZED(o, v) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o), v) + +#define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o)) + +#define _PyGC_REFS_UNTRACKED (-2) +#define _PyGC_REFS_REACHABLE (-3) +#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4) + +/* Tell the GC to track this object. NB: While the object is tracked the + * collector it must be safe to call the ob_traverse method. */ +#define _PyObject_GC_TRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + if (_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED) \ + Py_FatalError("GC object already tracked"); \ + _PyGCHead_SET_REFS(g, _PyGC_REFS_REACHABLE); \ + g->gc.gc_next = _PyGC_generation0; \ + g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \ + g->gc.gc_prev->gc.gc_next = g; \ + _PyGC_generation0->gc.gc_prev = g; \ + } while (0); + +/* Tell the GC to stop tracking this object. + * gc_next doesn't need to be set to NULL, but doing so is a good + * way to provoke memory errors if calling code is confused. + */ +#define _PyObject_GC_UNTRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + assert(_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED); \ + _PyGCHead_SET_REFS(g, _PyGC_REFS_UNTRACKED); \ + g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \ + g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \ + g->gc.gc_next = NULL; \ + } while (0); + +/* True if the object is currently tracked by the GC. */ +#define _PyObject_GC_IS_TRACKED(o) \ + (_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED) + +/* True if the object may be tracked by the GC in the future, or already is. + This can be useful to implement some optimizations. */ +#define _PyObject_GC_MAY_BE_TRACKED(obj) \ + (PyObject_IS_GC(obj) && \ + (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj))) +#endif /* Py_LIMITED_API */ + +PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size); +PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size); +PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *); +PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(void) PyObject_GC_Track(void *); +PyAPI_FUNC(void) PyObject_GC_UnTrack(void *); +PyAPI_FUNC(void) PyObject_GC_Del(void *); + +#define PyObject_GC_New(type, typeobj) \ + ( (type *) _PyObject_GC_New(typeobj) ) +#define PyObject_GC_NewVar(type, typeobj, n) \ + ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) + + +/* Utility macro to help write tp_traverse functions. + * To use this macro, the tp_traverse function must name its arguments + * "visit" and "arg". This is intended to keep tp_traverse functions + * looking as much alike as possible. + */ +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((PyObject *)(op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) + + +/* Test if a type supports weak references */ +#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0) + +#define PyObject_GET_WEAKREFS_LISTPTR(o) \ + ((PyObject **) (((char *) (o)) + Py_TYPE(o)->tp_weaklistoffset)) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OBJIMPL_H */ diff --git a/libs/nxpy/include/odictobject.h b/libs/nxpy/include/odictobject.h index c1d9592a..fe9cbdbd 100644 --- a/libs/nxpy/include/odictobject.h +++ b/libs/nxpy/include/odictobject.h @@ -1,43 +1,43 @@ -#ifndef Py_ODICTOBJECT_H -#define Py_ODICTOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* OrderedDict */ - -#ifndef Py_LIMITED_API - -typedef struct _odictobject PyODictObject; - -PyAPI_DATA(PyTypeObject) PyODict_Type; -PyAPI_DATA(PyTypeObject) PyODictIter_Type; -PyAPI_DATA(PyTypeObject) PyODictKeys_Type; -PyAPI_DATA(PyTypeObject) PyODictItems_Type; -PyAPI_DATA(PyTypeObject) PyODictValues_Type; - -#endif /* Py_LIMITED_API */ - -#define PyODict_Check(op) PyObject_TypeCheck(op, &PyODict_Type) -#define PyODict_CheckExact(op) (Py_TYPE(op) == &PyODict_Type) -#define PyODict_SIZE(op) ((PyDictObject *)op)->ma_used -#define PyODict_HasKey(od, key) (PyMapping_HasKey(PyObject *)od, key) - -PyAPI_FUNC(PyObject *) PyODict_New(void); -PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item); -PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key); - -/* wrappers around PyDict* functions */ -#define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key) -#define PyODict_GetItemWithError(od, key) \ - PyDict_GetItemWithError((PyObject *)od, key) -#define PyODict_Contains(od, key) PyDict_Contains((PyObject *)od, key) -#define PyODict_Size(od) PyDict_Size((PyObject *)od) -#define PyODict_GetItemString(od, key) \ - PyDict_GetItemString((PyObject *)od, key) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ODICTOBJECT_H */ +#ifndef Py_ODICTOBJECT_H +#define Py_ODICTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* OrderedDict */ + +#ifndef Py_LIMITED_API + +typedef struct _odictobject PyODictObject; + +PyAPI_DATA(PyTypeObject) PyODict_Type; +PyAPI_DATA(PyTypeObject) PyODictIter_Type; +PyAPI_DATA(PyTypeObject) PyODictKeys_Type; +PyAPI_DATA(PyTypeObject) PyODictItems_Type; +PyAPI_DATA(PyTypeObject) PyODictValues_Type; + +#endif /* Py_LIMITED_API */ + +#define PyODict_Check(op) PyObject_TypeCheck(op, &PyODict_Type) +#define PyODict_CheckExact(op) (Py_TYPE(op) == &PyODict_Type) +#define PyODict_SIZE(op) ((PyDictObject *)op)->ma_used +#define PyODict_HasKey(od, key) (PyMapping_HasKey(PyObject *)od, key) + +PyAPI_FUNC(PyObject *) PyODict_New(void); +PyAPI_FUNC(int) PyODict_SetItem(PyObject *od, PyObject *key, PyObject *item); +PyAPI_FUNC(int) PyODict_DelItem(PyObject *od, PyObject *key); + +/* wrappers around PyDict* functions */ +#define PyODict_GetItem(od, key) PyDict_GetItem((PyObject *)od, key) +#define PyODict_GetItemWithError(od, key) \ + PyDict_GetItemWithError((PyObject *)od, key) +#define PyODict_Contains(od, key) PyDict_Contains((PyObject *)od, key) +#define PyODict_Size(od) PyDict_Size((PyObject *)od) +#define PyODict_GetItemString(od, key) \ + PyDict_GetItemString((PyObject *)od, key) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ODICTOBJECT_H */ diff --git a/libs/nxpy/include/opcode.h b/libs/nxpy/include/opcode.h index 3f917fb6..4553a9be 100644 --- a/libs/nxpy/include/opcode.h +++ b/libs/nxpy/include/opcode.h @@ -1,142 +1,142 @@ -/* Auto-generated by Tools/scripts/generate_opcode_h.py */ -#ifndef Py_OPCODE_H -#define Py_OPCODE_H -#ifdef __cplusplus -extern "C" { -#endif - - - /* Instruction opcodes for compiled code */ -#define POP_TOP 1 -#define ROT_TWO 2 -#define ROT_THREE 3 -#define DUP_TOP 4 -#define DUP_TOP_TWO 5 -#define NOP 9 -#define UNARY_POSITIVE 10 -#define UNARY_NEGATIVE 11 -#define UNARY_NOT 12 -#define UNARY_INVERT 15 -#define BINARY_MATRIX_MULTIPLY 16 -#define INPLACE_MATRIX_MULTIPLY 17 -#define BINARY_POWER 19 -#define BINARY_MULTIPLY 20 -#define BINARY_MODULO 22 -#define BINARY_ADD 23 -#define BINARY_SUBTRACT 24 -#define BINARY_SUBSCR 25 -#define BINARY_FLOOR_DIVIDE 26 -#define BINARY_TRUE_DIVIDE 27 -#define INPLACE_FLOOR_DIVIDE 28 -#define INPLACE_TRUE_DIVIDE 29 -#define GET_AITER 50 -#define GET_ANEXT 51 -#define BEFORE_ASYNC_WITH 52 -#define INPLACE_ADD 55 -#define INPLACE_SUBTRACT 56 -#define INPLACE_MULTIPLY 57 -#define INPLACE_MODULO 59 -#define STORE_SUBSCR 60 -#define DELETE_SUBSCR 61 -#define BINARY_LSHIFT 62 -#define BINARY_RSHIFT 63 -#define BINARY_AND 64 -#define BINARY_XOR 65 -#define BINARY_OR 66 -#define INPLACE_POWER 67 -#define GET_ITER 68 -#define GET_YIELD_FROM_ITER 69 -#define PRINT_EXPR 70 -#define LOAD_BUILD_CLASS 71 -#define YIELD_FROM 72 -#define GET_AWAITABLE 73 -#define INPLACE_LSHIFT 75 -#define INPLACE_RSHIFT 76 -#define INPLACE_AND 77 -#define INPLACE_XOR 78 -#define INPLACE_OR 79 -#define BREAK_LOOP 80 -#define WITH_CLEANUP_START 81 -#define WITH_CLEANUP_FINISH 82 -#define RETURN_VALUE 83 -#define IMPORT_STAR 84 -#define YIELD_VALUE 86 -#define POP_BLOCK 87 -#define END_FINALLY 88 -#define POP_EXCEPT 89 -#define HAVE_ARGUMENT 90 -#define STORE_NAME 90 -#define DELETE_NAME 91 -#define UNPACK_SEQUENCE 92 -#define FOR_ITER 93 -#define UNPACK_EX 94 -#define STORE_ATTR 95 -#define DELETE_ATTR 96 -#define STORE_GLOBAL 97 -#define DELETE_GLOBAL 98 -#define LOAD_CONST 100 -#define LOAD_NAME 101 -#define BUILD_TUPLE 102 -#define BUILD_LIST 103 -#define BUILD_SET 104 -#define BUILD_MAP 105 -#define LOAD_ATTR 106 -#define COMPARE_OP 107 -#define IMPORT_NAME 108 -#define IMPORT_FROM 109 -#define JUMP_FORWARD 110 -#define JUMP_IF_FALSE_OR_POP 111 -#define JUMP_IF_TRUE_OR_POP 112 -#define JUMP_ABSOLUTE 113 -#define POP_JUMP_IF_FALSE 114 -#define POP_JUMP_IF_TRUE 115 -#define LOAD_GLOBAL 116 -#define CONTINUE_LOOP 119 -#define SETUP_LOOP 120 -#define SETUP_EXCEPT 121 -#define SETUP_FINALLY 122 -#define LOAD_FAST 124 -#define STORE_FAST 125 -#define DELETE_FAST 126 -#define RAISE_VARARGS 130 -#define CALL_FUNCTION 131 -#define MAKE_FUNCTION 132 -#define BUILD_SLICE 133 -#define MAKE_CLOSURE 134 -#define LOAD_CLOSURE 135 -#define LOAD_DEREF 136 -#define STORE_DEREF 137 -#define DELETE_DEREF 138 -#define CALL_FUNCTION_VAR 140 -#define CALL_FUNCTION_KW 141 -#define CALL_FUNCTION_VAR_KW 142 -#define SETUP_WITH 143 -#define EXTENDED_ARG 144 -#define LIST_APPEND 145 -#define SET_ADD 146 -#define MAP_ADD 147 -#define LOAD_CLASSDEREF 148 -#define BUILD_LIST_UNPACK 149 -#define BUILD_MAP_UNPACK 150 -#define BUILD_MAP_UNPACK_WITH_CALL 151 -#define BUILD_TUPLE_UNPACK 152 -#define BUILD_SET_UNPACK 153 -#define SETUP_ASYNC_WITH 154 - -/* EXCEPT_HANDLER is a special, implicit block type which is created when - entering an except handler. It is not an opcode but we define it here - as we want it to be available to both frameobject.c and ceval.c, while - remaining private.*/ -#define EXCEPT_HANDLER 257 - - -enum cmp_op {PyCmp_LT=Py_LT, PyCmp_LE=Py_LE, PyCmp_EQ=Py_EQ, PyCmp_NE=Py_NE, - PyCmp_GT=Py_GT, PyCmp_GE=Py_GE, PyCmp_IN, PyCmp_NOT_IN, - PyCmp_IS, PyCmp_IS_NOT, PyCmp_EXC_MATCH, PyCmp_BAD}; - -#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OPCODE_H */ +/* Auto-generated by Tools/scripts/generate_opcode_h.py */ +#ifndef Py_OPCODE_H +#define Py_OPCODE_H +#ifdef __cplusplus +extern "C" { +#endif + + + /* Instruction opcodes for compiled code */ +#define POP_TOP 1 +#define ROT_TWO 2 +#define ROT_THREE 3 +#define DUP_TOP 4 +#define DUP_TOP_TWO 5 +#define NOP 9 +#define UNARY_POSITIVE 10 +#define UNARY_NEGATIVE 11 +#define UNARY_NOT 12 +#define UNARY_INVERT 15 +#define BINARY_MATRIX_MULTIPLY 16 +#define INPLACE_MATRIX_MULTIPLY 17 +#define BINARY_POWER 19 +#define BINARY_MULTIPLY 20 +#define BINARY_MODULO 22 +#define BINARY_ADD 23 +#define BINARY_SUBTRACT 24 +#define BINARY_SUBSCR 25 +#define BINARY_FLOOR_DIVIDE 26 +#define BINARY_TRUE_DIVIDE 27 +#define INPLACE_FLOOR_DIVIDE 28 +#define INPLACE_TRUE_DIVIDE 29 +#define GET_AITER 50 +#define GET_ANEXT 51 +#define BEFORE_ASYNC_WITH 52 +#define INPLACE_ADD 55 +#define INPLACE_SUBTRACT 56 +#define INPLACE_MULTIPLY 57 +#define INPLACE_MODULO 59 +#define STORE_SUBSCR 60 +#define DELETE_SUBSCR 61 +#define BINARY_LSHIFT 62 +#define BINARY_RSHIFT 63 +#define BINARY_AND 64 +#define BINARY_XOR 65 +#define BINARY_OR 66 +#define INPLACE_POWER 67 +#define GET_ITER 68 +#define GET_YIELD_FROM_ITER 69 +#define PRINT_EXPR 70 +#define LOAD_BUILD_CLASS 71 +#define YIELD_FROM 72 +#define GET_AWAITABLE 73 +#define INPLACE_LSHIFT 75 +#define INPLACE_RSHIFT 76 +#define INPLACE_AND 77 +#define INPLACE_XOR 78 +#define INPLACE_OR 79 +#define BREAK_LOOP 80 +#define WITH_CLEANUP_START 81 +#define WITH_CLEANUP_FINISH 82 +#define RETURN_VALUE 83 +#define IMPORT_STAR 84 +#define YIELD_VALUE 86 +#define POP_BLOCK 87 +#define END_FINALLY 88 +#define POP_EXCEPT 89 +#define HAVE_ARGUMENT 90 +#define STORE_NAME 90 +#define DELETE_NAME 91 +#define UNPACK_SEQUENCE 92 +#define FOR_ITER 93 +#define UNPACK_EX 94 +#define STORE_ATTR 95 +#define DELETE_ATTR 96 +#define STORE_GLOBAL 97 +#define DELETE_GLOBAL 98 +#define LOAD_CONST 100 +#define LOAD_NAME 101 +#define BUILD_TUPLE 102 +#define BUILD_LIST 103 +#define BUILD_SET 104 +#define BUILD_MAP 105 +#define LOAD_ATTR 106 +#define COMPARE_OP 107 +#define IMPORT_NAME 108 +#define IMPORT_FROM 109 +#define JUMP_FORWARD 110 +#define JUMP_IF_FALSE_OR_POP 111 +#define JUMP_IF_TRUE_OR_POP 112 +#define JUMP_ABSOLUTE 113 +#define POP_JUMP_IF_FALSE 114 +#define POP_JUMP_IF_TRUE 115 +#define LOAD_GLOBAL 116 +#define CONTINUE_LOOP 119 +#define SETUP_LOOP 120 +#define SETUP_EXCEPT 121 +#define SETUP_FINALLY 122 +#define LOAD_FAST 124 +#define STORE_FAST 125 +#define DELETE_FAST 126 +#define RAISE_VARARGS 130 +#define CALL_FUNCTION 131 +#define MAKE_FUNCTION 132 +#define BUILD_SLICE 133 +#define MAKE_CLOSURE 134 +#define LOAD_CLOSURE 135 +#define LOAD_DEREF 136 +#define STORE_DEREF 137 +#define DELETE_DEREF 138 +#define CALL_FUNCTION_VAR 140 +#define CALL_FUNCTION_KW 141 +#define CALL_FUNCTION_VAR_KW 142 +#define SETUP_WITH 143 +#define EXTENDED_ARG 144 +#define LIST_APPEND 145 +#define SET_ADD 146 +#define MAP_ADD 147 +#define LOAD_CLASSDEREF 148 +#define BUILD_LIST_UNPACK 149 +#define BUILD_MAP_UNPACK 150 +#define BUILD_MAP_UNPACK_WITH_CALL 151 +#define BUILD_TUPLE_UNPACK 152 +#define BUILD_SET_UNPACK 153 +#define SETUP_ASYNC_WITH 154 + +/* EXCEPT_HANDLER is a special, implicit block type which is created when + entering an except handler. It is not an opcode but we define it here + as we want it to be available to both frameobject.c and ceval.c, while + remaining private.*/ +#define EXCEPT_HANDLER 257 + + +enum cmp_op {PyCmp_LT=Py_LT, PyCmp_LE=Py_LE, PyCmp_EQ=Py_EQ, PyCmp_NE=Py_NE, + PyCmp_GT=Py_GT, PyCmp_GE=Py_GE, PyCmp_IN, PyCmp_NOT_IN, + PyCmp_IS, PyCmp_IS_NOT, PyCmp_EXC_MATCH, PyCmp_BAD}; + +#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OPCODE_H */ diff --git a/libs/nxpy/include/osdefs.h b/libs/nxpy/include/osdefs.h index bd84c1c1..b6a12644 100644 --- a/libs/nxpy/include/osdefs.h +++ b/libs/nxpy/include/osdefs.h @@ -1,47 +1,47 @@ -#ifndef Py_OSDEFS_H -#define Py_OSDEFS_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Operating system dependencies */ - -#ifdef MS_WINDOWS -#define SEP L'\\' -#define ALTSEP L'/' -#define MAXPATHLEN 256 -#define DELIM L';' -#endif - -/* Filename separator */ -#ifndef SEP -#define SEP L'/' -#endif - -/* Max pathname length */ -#ifdef __hpux -#include -#include -#ifndef PATH_MAX -#define PATH_MAX MAXPATHLEN -#endif -#endif - -#ifndef MAXPATHLEN -#if defined(PATH_MAX) && PATH_MAX > 1024 -#define MAXPATHLEN PATH_MAX -#else -#define MAXPATHLEN 1024 -#endif -#endif - -/* Search path entry delimiter */ -#ifndef DELIM -#define DELIM L':' -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_OSDEFS_H */ +#ifndef Py_OSDEFS_H +#define Py_OSDEFS_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Operating system dependencies */ + +#ifdef MS_WINDOWS +#define SEP L'\\' +#define ALTSEP L'/' +#define MAXPATHLEN 256 +#define DELIM L';' +#endif + +/* Filename separator */ +#ifndef SEP +#define SEP L'/' +#endif + +/* Max pathname length */ +#ifdef __hpux +#include +#include +#ifndef PATH_MAX +#define PATH_MAX MAXPATHLEN +#endif +#endif + +#ifndef MAXPATHLEN +#if defined(PATH_MAX) && PATH_MAX > 1024 +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 1024 +#endif +#endif + +/* Search path entry delimiter */ +#ifndef DELIM +#define DELIM L':' +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OSDEFS_H */ diff --git a/libs/nxpy/include/parsetok.h b/libs/nxpy/include/parsetok.h index 2acb8546..07a3f2a2 100644 --- a/libs/nxpy/include/parsetok.h +++ b/libs/nxpy/include/parsetok.h @@ -1,108 +1,108 @@ - -/* Parser-tokenizer link interface */ -#ifndef Py_LIMITED_API -#ifndef Py_PARSETOK_H -#define Py_PARSETOK_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int error; -#ifndef PGEN - /* The filename is useless for pgen, see comment in tok_state structure */ - PyObject *filename; -#endif - int lineno; - int offset; - char *text; /* UTF-8-encoded string */ - int token; - int expected; -} perrdetail; - -#if 0 -#define PyPARSE_YIELD_IS_KEYWORD 0x0001 -#endif - -#define PyPARSE_DONT_IMPLY_DEDENT 0x0002 - -#if 0 -#define PyPARSE_WITH_IS_KEYWORD 0x0003 -#define PyPARSE_PRINT_IS_FUNCTION 0x0004 -#define PyPARSE_UNICODE_LITERALS 0x0008 -#endif - -#define PyPARSE_IGNORE_COOKIE 0x0010 -#define PyPARSE_BARRY_AS_BDFL 0x0020 - -PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, - perrdetail *); -PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, - const char *, const char *, - perrdetail *); - -PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int, - perrdetail *, int); -PyAPI_FUNC(node *) PyParser_ParseFileFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int flags); -PyAPI_FUNC(node *) PyParser_ParseFileFlagsEx( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int *flags); -PyAPI_FUNC(node *) PyParser_ParseFileObject( - FILE *fp, - PyObject *filename, - const char *enc, - grammar *g, - int start, - const char *ps1, - const char *ps2, - perrdetail *err_ret, - int *flags); - -PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilename( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - grammar *g, - int start, - perrdetail *err_ret, - int flags); -PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilenameEx( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - grammar *g, - int start, - perrdetail *err_ret, - int *flags); -PyAPI_FUNC(node *) PyParser_ParseStringObject( - const char *s, - PyObject *filename, - grammar *g, - int start, - perrdetail *err_ret, - int *flags); - -/* Note that the following functions are defined in pythonrun.c, - not in parsetok.c */ -PyAPI_FUNC(void) PyParser_SetError(perrdetail *); -PyAPI_FUNC(void) PyParser_ClearError(perrdetail *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PARSETOK_H */ -#endif /* !Py_LIMITED_API */ + +/* Parser-tokenizer link interface */ +#ifndef Py_LIMITED_API +#ifndef Py_PARSETOK_H +#define Py_PARSETOK_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int error; +#ifndef PGEN + /* The filename is useless for pgen, see comment in tok_state structure */ + PyObject *filename; +#endif + int lineno; + int offset; + char *text; /* UTF-8-encoded string */ + int token; + int expected; +} perrdetail; + +#if 0 +#define PyPARSE_YIELD_IS_KEYWORD 0x0001 +#endif + +#define PyPARSE_DONT_IMPLY_DEDENT 0x0002 + +#if 0 +#define PyPARSE_WITH_IS_KEYWORD 0x0003 +#define PyPARSE_PRINT_IS_FUNCTION 0x0004 +#define PyPARSE_UNICODE_LITERALS 0x0008 +#endif + +#define PyPARSE_IGNORE_COOKIE 0x0010 +#define PyPARSE_BARRY_AS_BDFL 0x0020 + +PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, + perrdetail *); +PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, + const char *, const char *, + perrdetail *); + +PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int, + perrdetail *, int); +PyAPI_FUNC(node *) PyParser_ParseFileFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + const char *enc, + grammar *g, + int start, + const char *ps1, + const char *ps2, + perrdetail *err_ret, + int flags); +PyAPI_FUNC(node *) PyParser_ParseFileFlagsEx( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + const char *enc, + grammar *g, + int start, + const char *ps1, + const char *ps2, + perrdetail *err_ret, + int *flags); +PyAPI_FUNC(node *) PyParser_ParseFileObject( + FILE *fp, + PyObject *filename, + const char *enc, + grammar *g, + int start, + const char *ps1, + const char *ps2, + perrdetail *err_ret, + int *flags); + +PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilename( + const char *s, + const char *filename, /* decoded from the filesystem encoding */ + grammar *g, + int start, + perrdetail *err_ret, + int flags); +PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilenameEx( + const char *s, + const char *filename, /* decoded from the filesystem encoding */ + grammar *g, + int start, + perrdetail *err_ret, + int *flags); +PyAPI_FUNC(node *) PyParser_ParseStringObject( + const char *s, + PyObject *filename, + grammar *g, + int start, + perrdetail *err_ret, + int *flags); + +/* Note that the following functions are defined in pythonrun.c, + not in parsetok.c */ +PyAPI_FUNC(void) PyParser_SetError(perrdetail *); +PyAPI_FUNC(void) PyParser_ClearError(perrdetail *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PARSETOK_H */ +#endif /* !Py_LIMITED_API */ diff --git a/libs/nxpy/include/patchlevel.h b/libs/nxpy/include/patchlevel.h index 77e72495..3f38f35b 100644 --- a/libs/nxpy/include/patchlevel.h +++ b/libs/nxpy/include/patchlevel.h @@ -1,35 +1,35 @@ - -/* Python version identification scheme. - - When the major or minor version changes, the VERSION variable in - configure.ac must also be changed. - - There is also (independent) API version information in modsupport.h. -*/ - -/* Values for PY_RELEASE_LEVEL */ -#define PY_RELEASE_LEVEL_ALPHA 0xA -#define PY_RELEASE_LEVEL_BETA 0xB -#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ -#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ - /* Higher for patch releases */ - -/* Version parsed out into numeric values */ -/*--start constants--*/ -#define PY_MAJOR_VERSION 3 -#define PY_MINOR_VERSION 5 -#define PY_MICRO_VERSION 3 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 - -/* Version as a string */ -#define PY_VERSION "3.5.3" -/*--end constants--*/ - -/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. - Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ -#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ - (PY_MINOR_VERSION << 16) | \ - (PY_MICRO_VERSION << 8) | \ - (PY_RELEASE_LEVEL << 4) | \ - (PY_RELEASE_SERIAL << 0)) + +/* Python version identification scheme. + + When the major or minor version changes, the VERSION variable in + configure.ac must also be changed. + + There is also (independent) API version information in modsupport.h. +*/ + +/* Values for PY_RELEASE_LEVEL */ +#define PY_RELEASE_LEVEL_ALPHA 0xA +#define PY_RELEASE_LEVEL_BETA 0xB +#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ +#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ + /* Higher for patch releases */ + +/* Version parsed out into numeric values */ +/*--start constants--*/ +#define PY_MAJOR_VERSION 3 +#define PY_MINOR_VERSION 5 +#define PY_MICRO_VERSION 3 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 + +/* Version as a string */ +#define PY_VERSION "3.5.3" +/*--end constants--*/ + +/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. + Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ +#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ + (PY_MINOR_VERSION << 16) | \ + (PY_MICRO_VERSION << 8) | \ + (PY_RELEASE_LEVEL << 4) | \ + (PY_RELEASE_SERIAL << 0)) diff --git a/libs/nxpy/include/pgen.h b/libs/nxpy/include/pgen.h index 8a325ed0..af84852b 100644 --- a/libs/nxpy/include/pgen.h +++ b/libs/nxpy/include/pgen.h @@ -1,18 +1,18 @@ -#ifndef Py_PGEN_H -#define Py_PGEN_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Parser generator interface */ - -extern grammar *meta_grammar(void); - -struct _node; -extern grammar *pgen(struct _node *); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PGEN_H */ +#ifndef Py_PGEN_H +#define Py_PGEN_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Parser generator interface */ + +extern grammar *meta_grammar(void); + +struct _node; +extern grammar *pgen(struct _node *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PGEN_H */ diff --git a/libs/nxpy/include/pgenheaders.h b/libs/nxpy/include/pgenheaders.h index 2049ae32..7aac4e2b 100644 --- a/libs/nxpy/include/pgenheaders.h +++ b/libs/nxpy/include/pgenheaders.h @@ -1,42 +1,42 @@ -#ifndef Py_PGENHEADERS_H -#define Py_PGENHEADERS_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Include files and extern declarations used by most of the parser. */ - -#include "Python.h" - -PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); - -#define addarc _Py_addarc -#define addbit _Py_addbit -#define adddfa _Py_adddfa -#define addfirstsets _Py_addfirstsets -#define addlabel _Py_addlabel -#define addstate _Py_addstate -#define delbitset _Py_delbitset -#define dumptree _Py_dumptree -#define findlabel _Py_findlabel -#define mergebitset _Py_mergebitset -#define meta_grammar _Py_meta_grammar -#define newbitset _Py_newbitset -#define newgrammar _Py_newgrammar -#define pgen _Py_pgen -#define printgrammar _Py_printgrammar -#define printnonterminals _Py_printnonterminals -#define printtree _Py_printtree -#define samebitset _Py_samebitset -#define showtree _Py_showtree -#define tok_dump _Py_tok_dump -#define translatelabels _Py_translatelabels - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PGENHEADERS_H */ +#ifndef Py_PGENHEADERS_H +#define Py_PGENHEADERS_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Include files and extern declarations used by most of the parser. */ + +#include "Python.h" + +PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); + +#define addarc _Py_addarc +#define addbit _Py_addbit +#define adddfa _Py_adddfa +#define addfirstsets _Py_addfirstsets +#define addlabel _Py_addlabel +#define addstate _Py_addstate +#define delbitset _Py_delbitset +#define dumptree _Py_dumptree +#define findlabel _Py_findlabel +#define mergebitset _Py_mergebitset +#define meta_grammar _Py_meta_grammar +#define newbitset _Py_newbitset +#define newgrammar _Py_newgrammar +#define pgen _Py_pgen +#define printgrammar _Py_printgrammar +#define printnonterminals _Py_printnonterminals +#define printtree _Py_printtree +#define samebitset _Py_samebitset +#define showtree _Py_showtree +#define tok_dump _Py_tok_dump +#define translatelabels _Py_translatelabels + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PGENHEADERS_H */ diff --git a/libs/nxpy/include/py_curses.h b/libs/nxpy/include/py_curses.h index f2c08f64..5e8e95b2 100644 --- a/libs/nxpy/include/py_curses.h +++ b/libs/nxpy/include/py_curses.h @@ -1,177 +1,177 @@ - -#ifndef Py_CURSES_H -#define Py_CURSES_H - -#ifdef __APPLE__ -/* -** On Mac OS X 10.2 [n]curses.h and stdlib.h use different guards -** against multiple definition of wchar_t. -*/ -#ifdef _BSD_WCHAR_T_DEFINED_ -#define _WCHAR_T -#endif - -/* the following define is necessary for OS X 10.6; without it, the - Apple-supplied ncurses.h sets NCURSES_OPAQUE to 1, and then Python - can't get at the WINDOW flags field. */ -#define NCURSES_OPAQUE 0 -#endif /* __APPLE__ */ - -#ifdef __FreeBSD__ -/* -** On FreeBSD, [n]curses.h and stdlib.h/wchar.h use different guards -** against multiple definition of wchar_t and wint_t. -*/ -#ifdef _XOPEN_SOURCE_EXTENDED -#ifndef __FreeBSD_version -#include -#endif -#if __FreeBSD_version >= 500000 -#ifndef __wchar_t -#define __wchar_t -#endif -#ifndef __wint_t -#define __wint_t -#endif -#else -#ifndef _WCHAR_T -#define _WCHAR_T -#endif -#ifndef _WINT_T -#define _WINT_T -#endif -#endif -#endif -#endif - -#ifdef HAVE_NCURSES_H -#include -#else -#include -#ifdef HAVE_TERM_H -/* for tigetstr, which is not declared in SysV curses */ -#include -#endif -#endif - -#ifdef HAVE_NCURSES_H -/* configure was checking , but we will - use , which has all these features. */ -#ifndef WINDOW_HAS_FLAGS -#define WINDOW_HAS_FLAGS 1 -#endif -#ifndef MVWDELCH_IS_EXPRESSION -#define MVWDELCH_IS_EXPRESSION 1 -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define PyCurses_API_pointers 4 - -/* Type declarations */ - -typedef struct { - PyObject_HEAD - WINDOW *win; - char *encoding; -} PyCursesWindowObject; - -#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type) - -#define PyCurses_CAPSULE_NAME "_curses._C_API" - - -#ifdef CURSES_MODULE -/* This section is used when compiling _cursesmodule.c */ - -#else -/* This section is used in modules that use the _cursesmodule API */ - -static void **PyCurses_API; - -#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0]) -#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} -#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} -#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} - -#define import_curses() \ - PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1); - -#endif - -/* general error messages */ -static char *catchall_ERR = "curses function returned ERR"; -static char *catchall_NULL = "curses function returned NULL"; - -/* Function Prototype Macros - They are ugly but very, very useful. ;-) - - X - function name - TYPE - parameter Type - ERGSTR - format string for construction of the return value - PARSESTR - format string for argument parsing - */ - -#define NoArgNoReturnFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self) \ -{ \ - PyCursesInitialised \ - return PyCursesCheckERR(X(), # X); } - -#define NoArgOrFlagNoReturnFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self, PyObject *args) \ -{ \ - int flag = 0; \ - PyCursesInitialised \ - switch(PyTuple_Size(args)) { \ - case 0: \ - return PyCursesCheckERR(X(), # X); \ - case 1: \ - if (!PyArg_ParseTuple(args, "i;True(1) or False(0)", &flag)) return NULL; \ - if (flag) return PyCursesCheckERR(X(), # X); \ - else return PyCursesCheckERR(no ## X (), # X); \ - default: \ - PyErr_SetString(PyExc_TypeError, # X " requires 0 or 1 arguments"); \ - return NULL; } } - -#define NoArgReturnIntFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self) \ -{ \ - PyCursesInitialised \ - return PyLong_FromLong((long) X()); } - - -#define NoArgReturnStringFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self) \ -{ \ - PyCursesInitialised \ - return PyBytes_FromString(X()); } - -#define NoArgTrueFalseFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self) \ -{ \ - PyCursesInitialised \ - if (X () == FALSE) { \ - Py_INCREF(Py_False); \ - return Py_False; \ - } \ - Py_INCREF(Py_True); \ - return Py_True; } - -#define NoArgNoReturnVoidFunction(X) \ -static PyObject *PyCurses_ ## X (PyObject *self) \ -{ \ - PyCursesInitialised \ - X(); \ - Py_INCREF(Py_None); \ - return Py_None; } - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(Py_CURSES_H) */ - - + +#ifndef Py_CURSES_H +#define Py_CURSES_H + +#ifdef __APPLE__ +/* +** On Mac OS X 10.2 [n]curses.h and stdlib.h use different guards +** against multiple definition of wchar_t. +*/ +#ifdef _BSD_WCHAR_T_DEFINED_ +#define _WCHAR_T +#endif + +/* the following define is necessary for OS X 10.6; without it, the + Apple-supplied ncurses.h sets NCURSES_OPAQUE to 1, and then Python + can't get at the WINDOW flags field. */ +#define NCURSES_OPAQUE 0 +#endif /* __APPLE__ */ + +#ifdef __FreeBSD__ +/* +** On FreeBSD, [n]curses.h and stdlib.h/wchar.h use different guards +** against multiple definition of wchar_t and wint_t. +*/ +#ifdef _XOPEN_SOURCE_EXTENDED +#ifndef __FreeBSD_version +#include +#endif +#if __FreeBSD_version >= 500000 +#ifndef __wchar_t +#define __wchar_t +#endif +#ifndef __wint_t +#define __wint_t +#endif +#else +#ifndef _WCHAR_T +#define _WCHAR_T +#endif +#ifndef _WINT_T +#define _WINT_T +#endif +#endif +#endif +#endif + +#ifdef HAVE_NCURSES_H +#include +#else +#include +#ifdef HAVE_TERM_H +/* for tigetstr, which is not declared in SysV curses */ +#include +#endif +#endif + +#ifdef HAVE_NCURSES_H +/* configure was checking , but we will + use , which has all these features. */ +#ifndef WINDOW_HAS_FLAGS +#define WINDOW_HAS_FLAGS 1 +#endif +#ifndef MVWDELCH_IS_EXPRESSION +#define MVWDELCH_IS_EXPRESSION 1 +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PyCurses_API_pointers 4 + +/* Type declarations */ + +typedef struct { + PyObject_HEAD + WINDOW *win; + char *encoding; +} PyCursesWindowObject; + +#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type) + +#define PyCurses_CAPSULE_NAME "_curses._C_API" + + +#ifdef CURSES_MODULE +/* This section is used when compiling _cursesmodule.c */ + +#else +/* This section is used in modules that use the _cursesmodule API */ + +static void **PyCurses_API; + +#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0]) +#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} +#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} +#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} + +#define import_curses() \ + PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1); + +#endif + +/* general error messages */ +static char *catchall_ERR = "curses function returned ERR"; +static char *catchall_NULL = "curses function returned NULL"; + +/* Function Prototype Macros - They are ugly but very, very useful. ;-) + + X - function name + TYPE - parameter Type + ERGSTR - format string for construction of the return value + PARSESTR - format string for argument parsing + */ + +#define NoArgNoReturnFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyCursesCheckERR(X(), # X); } + +#define NoArgOrFlagNoReturnFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self, PyObject *args) \ +{ \ + int flag = 0; \ + PyCursesInitialised \ + switch(PyTuple_Size(args)) { \ + case 0: \ + return PyCursesCheckERR(X(), # X); \ + case 1: \ + if (!PyArg_ParseTuple(args, "i;True(1) or False(0)", &flag)) return NULL; \ + if (flag) return PyCursesCheckERR(X(), # X); \ + else return PyCursesCheckERR(no ## X (), # X); \ + default: \ + PyErr_SetString(PyExc_TypeError, # X " requires 0 or 1 arguments"); \ + return NULL; } } + +#define NoArgReturnIntFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyLong_FromLong((long) X()); } + + +#define NoArgReturnStringFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyBytes_FromString(X()); } + +#define NoArgTrueFalseFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + if (X () == FALSE) { \ + Py_INCREF(Py_False); \ + return Py_False; \ + } \ + Py_INCREF(Py_True); \ + return Py_True; } + +#define NoArgNoReturnVoidFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + X(); \ + Py_INCREF(Py_None); \ + return Py_None; } + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(Py_CURSES_H) */ + + diff --git a/libs/nxpy/include/pyarena.h b/libs/nxpy/include/pyarena.h index db3ad018..97791bec 100644 --- a/libs/nxpy/include/pyarena.h +++ b/libs/nxpy/include/pyarena.h @@ -1,64 +1,64 @@ -/* An arena-like memory interface for the compiler. - */ - -#ifndef Py_LIMITED_API -#ifndef Py_PYARENA_H -#define Py_PYARENA_H - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct _arena PyArena; - - /* PyArena_New() and PyArena_Free() create a new arena and free it, - respectively. Once an arena has been created, it can be used - to allocate memory via PyArena_Malloc(). Pointers to PyObject can - also be registered with the arena via PyArena_AddPyObject(), and the - arena will ensure that the PyObjects stay alive at least until - PyArena_Free() is called. When an arena is freed, all the memory it - allocated is freed, the arena releases internal references to registered - PyObject*, and none of its pointers are valid. - XXX (tim) What does "none of its pointers are valid" mean? Does it - XXX mean that pointers previously obtained via PyArena_Malloc() are - XXX no longer valid? (That's clearly true, but not sure that's what - XXX the text is trying to say.) - - PyArena_New() returns an arena pointer. On error, it - returns a negative number and sets an exception. - XXX (tim): Not true. On error, PyArena_New() actually returns NULL, - XXX and looks like it may or may not set an exception (e.g., if the - XXX internal PyList_New(0) returns NULL, PyArena_New() passes that on - XXX and an exception is set; OTOH, if the internal - XXX block_new(DEFAULT_BLOCK_SIZE) returns NULL, that's passed on but - XXX an exception is not set in that case). - */ - PyAPI_FUNC(PyArena *) PyArena_New(void); - PyAPI_FUNC(void) PyArena_Free(PyArena *); - - /* Mostly like malloc(), return the address of a block of memory spanning - * `size` bytes, or return NULL (without setting an exception) if enough - * new memory can't be obtained. Unlike malloc(0), PyArena_Malloc() with - * size=0 does not guarantee to return a unique pointer (the pointer - * returned may equal one or more other pointers obtained from - * PyArena_Malloc()). - * Note that pointers obtained via PyArena_Malloc() must never be passed to - * the system free() or realloc(), or to any of Python's similar memory- - * management functions. PyArena_Malloc()-obtained pointers remain valid - * until PyArena_Free(ar) is called, at which point all pointers obtained - * from the arena `ar` become invalid simultaneously. - */ - PyAPI_FUNC(void *) PyArena_Malloc(PyArena *, size_t size); - - /* This routine isn't a proper arena allocation routine. It takes - * a PyObject* and records it so that it can be DECREFed when the - * arena is freed. - */ - PyAPI_FUNC(int) PyArena_AddPyObject(PyArena *, PyObject *); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYARENA_H */ -#endif /* Py_LIMITED_API */ +/* An arena-like memory interface for the compiler. + */ + +#ifndef Py_LIMITED_API +#ifndef Py_PYARENA_H +#define Py_PYARENA_H + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _arena PyArena; + + /* PyArena_New() and PyArena_Free() create a new arena and free it, + respectively. Once an arena has been created, it can be used + to allocate memory via PyArena_Malloc(). Pointers to PyObject can + also be registered with the arena via PyArena_AddPyObject(), and the + arena will ensure that the PyObjects stay alive at least until + PyArena_Free() is called. When an arena is freed, all the memory it + allocated is freed, the arena releases internal references to registered + PyObject*, and none of its pointers are valid. + XXX (tim) What does "none of its pointers are valid" mean? Does it + XXX mean that pointers previously obtained via PyArena_Malloc() are + XXX no longer valid? (That's clearly true, but not sure that's what + XXX the text is trying to say.) + + PyArena_New() returns an arena pointer. On error, it + returns a negative number and sets an exception. + XXX (tim): Not true. On error, PyArena_New() actually returns NULL, + XXX and looks like it may or may not set an exception (e.g., if the + XXX internal PyList_New(0) returns NULL, PyArena_New() passes that on + XXX and an exception is set; OTOH, if the internal + XXX block_new(DEFAULT_BLOCK_SIZE) returns NULL, that's passed on but + XXX an exception is not set in that case). + */ + PyAPI_FUNC(PyArena *) PyArena_New(void); + PyAPI_FUNC(void) PyArena_Free(PyArena *); + + /* Mostly like malloc(), return the address of a block of memory spanning + * `size` bytes, or return NULL (without setting an exception) if enough + * new memory can't be obtained. Unlike malloc(0), PyArena_Malloc() with + * size=0 does not guarantee to return a unique pointer (the pointer + * returned may equal one or more other pointers obtained from + * PyArena_Malloc()). + * Note that pointers obtained via PyArena_Malloc() must never be passed to + * the system free() or realloc(), or to any of Python's similar memory- + * management functions. PyArena_Malloc()-obtained pointers remain valid + * until PyArena_Free(ar) is called, at which point all pointers obtained + * from the arena `ar` become invalid simultaneously. + */ + PyAPI_FUNC(void *) PyArena_Malloc(PyArena *, size_t size); + + /* This routine isn't a proper arena allocation routine. It takes + * a PyObject* and records it so that it can be DECREFed when the + * arena is freed. + */ + PyAPI_FUNC(int) PyArena_AddPyObject(PyArena *, PyObject *); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYARENA_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/pyatomic.h b/libs/nxpy/include/pyatomic.h index 527aeb87..db1aba1e 100644 --- a/libs/nxpy/include/pyatomic.h +++ b/libs/nxpy/include/pyatomic.h @@ -1,250 +1,250 @@ -#ifndef Py_ATOMIC_H -#define Py_ATOMIC_H -#if defined(Py_BUILD_CORE) && !defined(__cplusplus) - -#include "dynamic_annotations.h" - -#include "pyconfig.h" - -#if defined(HAVE_STD_ATOMIC) -#include -#endif - -/* This is modeled after the atomics interface from C1x, according to - * the draft at - * http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1425.pdf. - * Operations and types are named the same except with a _Py_ prefix - * and have the same semantics. - * - * Beware, the implementations here are deep magic. - */ - -#if defined(HAVE_STD_ATOMIC) - -typedef enum _Py_memory_order { - _Py_memory_order_relaxed = memory_order_relaxed, - _Py_memory_order_acquire = memory_order_acquire, - _Py_memory_order_release = memory_order_release, - _Py_memory_order_acq_rel = memory_order_acq_rel, - _Py_memory_order_seq_cst = memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - atomic_uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - atomic_int _value; -} _Py_atomic_int; - -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ - atomic_signal_fence(ORDER) - -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ - atomic_thread_fence(ORDER) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER) - -/* Use builtin atomic operations in GCC >= 4.7 */ -#elif defined(HAVE_BUILTIN_ATOMIC) - -typedef enum _Py_memory_order { - _Py_memory_order_relaxed = __ATOMIC_RELAXED, - _Py_memory_order_acquire = __ATOMIC_ACQUIRE, - _Py_memory_order_release = __ATOMIC_RELEASE, - _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL, - _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST -} _Py_memory_order; - -typedef struct _Py_atomic_address { - Py_uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - int _value; -} _Py_atomic_int; - -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ - __atomic_signal_fence(ORDER) - -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ - __atomic_thread_fence(ORDER) - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - (assert((ORDER) == __ATOMIC_RELAXED \ - || (ORDER) == __ATOMIC_SEQ_CST \ - || (ORDER) == __ATOMIC_RELEASE), \ - __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - (assert((ORDER) == __ATOMIC_RELAXED \ - || (ORDER) == __ATOMIC_SEQ_CST \ - || (ORDER) == __ATOMIC_ACQUIRE \ - || (ORDER) == __ATOMIC_CONSUME), \ - __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER)) - -#else - -typedef enum _Py_memory_order { - _Py_memory_order_relaxed, - _Py_memory_order_acquire, - _Py_memory_order_release, - _Py_memory_order_acq_rel, - _Py_memory_order_seq_cst -} _Py_memory_order; - -typedef struct _Py_atomic_address { - Py_uintptr_t _value; -} _Py_atomic_address; - -typedef struct _Py_atomic_int { - int _value; -} _Py_atomic_int; - -/* Only support GCC (for expression statements) and x86 (for simple - * atomic semantics) for now */ -#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64)) - -static __inline__ void -_Py_atomic_signal_fence(_Py_memory_order order) -{ - if (order != _Py_memory_order_relaxed) - __asm__ volatile("":::"memory"); -} - -static __inline__ void -_Py_atomic_thread_fence(_Py_memory_order order) -{ - if (order != _Py_memory_order_relaxed) - __asm__ volatile("mfence":::"memory"); -} - -/* Tell the race checker about this operation's effects. */ -static __inline__ void -_Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order) -{ - (void)address; /* shut up -Wunused-parameter */ - switch(order) { - case _Py_memory_order_release: - case _Py_memory_order_acq_rel: - case _Py_memory_order_seq_cst: - _Py_ANNOTATE_HAPPENS_BEFORE(address); - break; - case _Py_memory_order_relaxed: - case _Py_memory_order_acquire: - break; - } - switch(order) { - case _Py_memory_order_acquire: - case _Py_memory_order_acq_rel: - case _Py_memory_order_seq_cst: - _Py_ANNOTATE_HAPPENS_AFTER(address); - break; - case _Py_memory_order_relaxed: - case _Py_memory_order_release: - break; - } -} - -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - __extension__ ({ \ - __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ - __typeof__(atomic_val->_value) new_val = NEW_VAL;\ - volatile __typeof__(new_val) *volatile_data = &atomic_val->_value; \ - _Py_memory_order order = ORDER; \ - _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ - \ - /* Perform the operation. */ \ - _Py_ANNOTATE_IGNORE_WRITES_BEGIN(); \ - switch(order) { \ - case _Py_memory_order_release: \ - _Py_atomic_signal_fence(_Py_memory_order_release); \ - /* fallthrough */ \ - case _Py_memory_order_relaxed: \ - *volatile_data = new_val; \ - break; \ - \ - case _Py_memory_order_acquire: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - __asm__ volatile("xchg %0, %1" \ - : "+r"(new_val) \ - : "m"(atomic_val->_value) \ - : "memory"); \ - break; \ - } \ - _Py_ANNOTATE_IGNORE_WRITES_END(); \ - }) - -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - __extension__ ({ \ - __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ - __typeof__(atomic_val->_value) result; \ - volatile __typeof__(result) *volatile_data = &atomic_val->_value; \ - _Py_memory_order order = ORDER; \ - _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ - \ - /* Perform the operation. */ \ - _Py_ANNOTATE_IGNORE_READS_BEGIN(); \ - switch(order) { \ - case _Py_memory_order_release: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - /* Loads on x86 are not releases by default, so need a */ \ - /* thread fence. */ \ - _Py_atomic_thread_fence(_Py_memory_order_release); \ - break; \ - default: \ - /* No fence */ \ - break; \ - } \ - result = *volatile_data; \ - switch(order) { \ - case _Py_memory_order_acquire: \ - case _Py_memory_order_acq_rel: \ - case _Py_memory_order_seq_cst: \ - /* Loads on x86 are automatically acquire operations so */ \ - /* can get by with just a compiler fence. */ \ - _Py_atomic_signal_fence(_Py_memory_order_acquire); \ - break; \ - default: \ - /* No fence */ \ - break; \ - } \ - _Py_ANNOTATE_IGNORE_READS_END(); \ - result; \ - }) - -#else /* !gcc x86 */ -/* Fall back to other compilers and processors by assuming that simple - volatile accesses are atomic. This is false, so people should port - this. */ -#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) ((void)0) -#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) ((void)0) -#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ - ((ATOMIC_VAL)->_value = NEW_VAL) -#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ - ((ATOMIC_VAL)->_value) - -#endif /* !gcc x86 */ -#endif - -/* Standardized shortcuts. */ -#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \ - _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_seq_cst) -#define _Py_atomic_load(ATOMIC_VAL) \ - _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_seq_cst) - -/* Python-local extensions */ - -#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ - _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_relaxed) -#define _Py_atomic_load_relaxed(ATOMIC_VAL) \ - _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_relaxed) - -#endif /* Py_BUILD_CORE */ -#endif /* Py_ATOMIC_H */ +#ifndef Py_ATOMIC_H +#define Py_ATOMIC_H +#if defined(Py_BUILD_CORE) && !defined(__cplusplus) + +#include "dynamic_annotations.h" + +#include "pyconfig.h" + +#if defined(HAVE_STD_ATOMIC) +#include +#endif + +/* This is modeled after the atomics interface from C1x, according to + * the draft at + * http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1425.pdf. + * Operations and types are named the same except with a _Py_ prefix + * and have the same semantics. + * + * Beware, the implementations here are deep magic. + */ + +#if defined(HAVE_STD_ATOMIC) + +typedef enum _Py_memory_order { + _Py_memory_order_relaxed = memory_order_relaxed, + _Py_memory_order_acquire = memory_order_acquire, + _Py_memory_order_release = memory_order_release, + _Py_memory_order_acq_rel = memory_order_acq_rel, + _Py_memory_order_seq_cst = memory_order_seq_cst +} _Py_memory_order; + +typedef struct _Py_atomic_address { + atomic_uintptr_t _value; +} _Py_atomic_address; + +typedef struct _Py_atomic_int { + atomic_int _value; +} _Py_atomic_int; + +#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ + atomic_signal_fence(ORDER) + +#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ + atomic_thread_fence(ORDER) + +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER) + +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER) + +/* Use builtin atomic operations in GCC >= 4.7 */ +#elif defined(HAVE_BUILTIN_ATOMIC) + +typedef enum _Py_memory_order { + _Py_memory_order_relaxed = __ATOMIC_RELAXED, + _Py_memory_order_acquire = __ATOMIC_ACQUIRE, + _Py_memory_order_release = __ATOMIC_RELEASE, + _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL, + _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST +} _Py_memory_order; + +typedef struct _Py_atomic_address { + Py_uintptr_t _value; +} _Py_atomic_address; + +typedef struct _Py_atomic_int { + int _value; +} _Py_atomic_int; + +#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ + __atomic_signal_fence(ORDER) + +#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ + __atomic_thread_fence(ORDER) + +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + (assert((ORDER) == __ATOMIC_RELAXED \ + || (ORDER) == __ATOMIC_SEQ_CST \ + || (ORDER) == __ATOMIC_RELEASE), \ + __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)) + +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + (assert((ORDER) == __ATOMIC_RELAXED \ + || (ORDER) == __ATOMIC_SEQ_CST \ + || (ORDER) == __ATOMIC_ACQUIRE \ + || (ORDER) == __ATOMIC_CONSUME), \ + __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER)) + +#else + +typedef enum _Py_memory_order { + _Py_memory_order_relaxed, + _Py_memory_order_acquire, + _Py_memory_order_release, + _Py_memory_order_acq_rel, + _Py_memory_order_seq_cst +} _Py_memory_order; + +typedef struct _Py_atomic_address { + Py_uintptr_t _value; +} _Py_atomic_address; + +typedef struct _Py_atomic_int { + int _value; +} _Py_atomic_int; + +/* Only support GCC (for expression statements) and x86 (for simple + * atomic semantics) for now */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64)) + +static __inline__ void +_Py_atomic_signal_fence(_Py_memory_order order) +{ + if (order != _Py_memory_order_relaxed) + __asm__ volatile("":::"memory"); +} + +static __inline__ void +_Py_atomic_thread_fence(_Py_memory_order order) +{ + if (order != _Py_memory_order_relaxed) + __asm__ volatile("mfence":::"memory"); +} + +/* Tell the race checker about this operation's effects. */ +static __inline__ void +_Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order) +{ + (void)address; /* shut up -Wunused-parameter */ + switch(order) { + case _Py_memory_order_release: + case _Py_memory_order_acq_rel: + case _Py_memory_order_seq_cst: + _Py_ANNOTATE_HAPPENS_BEFORE(address); + break; + case _Py_memory_order_relaxed: + case _Py_memory_order_acquire: + break; + } + switch(order) { + case _Py_memory_order_acquire: + case _Py_memory_order_acq_rel: + case _Py_memory_order_seq_cst: + _Py_ANNOTATE_HAPPENS_AFTER(address); + break; + case _Py_memory_order_relaxed: + case _Py_memory_order_release: + break; + } +} + +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + __extension__ ({ \ + __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ + __typeof__(atomic_val->_value) new_val = NEW_VAL;\ + volatile __typeof__(new_val) *volatile_data = &atomic_val->_value; \ + _Py_memory_order order = ORDER; \ + _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ + \ + /* Perform the operation. */ \ + _Py_ANNOTATE_IGNORE_WRITES_BEGIN(); \ + switch(order) { \ + case _Py_memory_order_release: \ + _Py_atomic_signal_fence(_Py_memory_order_release); \ + /* fallthrough */ \ + case _Py_memory_order_relaxed: \ + *volatile_data = new_val; \ + break; \ + \ + case _Py_memory_order_acquire: \ + case _Py_memory_order_acq_rel: \ + case _Py_memory_order_seq_cst: \ + __asm__ volatile("xchg %0, %1" \ + : "+r"(new_val) \ + : "m"(atomic_val->_value) \ + : "memory"); \ + break; \ + } \ + _Py_ANNOTATE_IGNORE_WRITES_END(); \ + }) + +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + __extension__ ({ \ + __typeof__(ATOMIC_VAL) atomic_val = ATOMIC_VAL; \ + __typeof__(atomic_val->_value) result; \ + volatile __typeof__(result) *volatile_data = &atomic_val->_value; \ + _Py_memory_order order = ORDER; \ + _Py_ANNOTATE_MEMORY_ORDER(atomic_val, order); \ + \ + /* Perform the operation. */ \ + _Py_ANNOTATE_IGNORE_READS_BEGIN(); \ + switch(order) { \ + case _Py_memory_order_release: \ + case _Py_memory_order_acq_rel: \ + case _Py_memory_order_seq_cst: \ + /* Loads on x86 are not releases by default, so need a */ \ + /* thread fence. */ \ + _Py_atomic_thread_fence(_Py_memory_order_release); \ + break; \ + default: \ + /* No fence */ \ + break; \ + } \ + result = *volatile_data; \ + switch(order) { \ + case _Py_memory_order_acquire: \ + case _Py_memory_order_acq_rel: \ + case _Py_memory_order_seq_cst: \ + /* Loads on x86 are automatically acquire operations so */ \ + /* can get by with just a compiler fence. */ \ + _Py_atomic_signal_fence(_Py_memory_order_acquire); \ + break; \ + default: \ + /* No fence */ \ + break; \ + } \ + _Py_ANNOTATE_IGNORE_READS_END(); \ + result; \ + }) + +#else /* !gcc x86 */ +/* Fall back to other compilers and processors by assuming that simple + volatile accesses are atomic. This is false, so people should port + this. */ +#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) ((void)0) +#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) ((void)0) +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + ((ATOMIC_VAL)->_value = NEW_VAL) +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + ((ATOMIC_VAL)->_value) + +#endif /* !gcc x86 */ +#endif + +/* Standardized shortcuts. */ +#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \ + _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_seq_cst) +#define _Py_atomic_load(ATOMIC_VAL) \ + _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_seq_cst) + +/* Python-local extensions */ + +#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ + _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, _Py_memory_order_relaxed) +#define _Py_atomic_load_relaxed(ATOMIC_VAL) \ + _Py_atomic_load_explicit(ATOMIC_VAL, _Py_memory_order_relaxed) + +#endif /* Py_BUILD_CORE */ +#endif /* Py_ATOMIC_H */ diff --git a/libs/nxpy/include/pycapsule.h b/libs/nxpy/include/pycapsule.h index d9ecda7a..358501e3 100644 --- a/libs/nxpy/include/pycapsule.h +++ b/libs/nxpy/include/pycapsule.h @@ -1,59 +1,59 @@ - -/* Capsule objects let you wrap a C "void *" pointer in a Python - object. They're a way of passing data through the Python interpreter - without creating your own custom type. - - Capsules are used for communication between extension modules. - They provide a way for an extension module to export a C interface - to other extension modules, so that extension modules can use the - Python import mechanism to link to one another. - - For more information, please see "c-api/capsule.html" in the - documentation. -*/ - -#ifndef Py_CAPSULE_H -#define Py_CAPSULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_DATA(PyTypeObject) PyCapsule_Type; - -typedef void (*PyCapsule_Destructor)(PyObject *); - -#define PyCapsule_CheckExact(op) (Py_TYPE(op) == &PyCapsule_Type) - - -PyAPI_FUNC(PyObject *) PyCapsule_New( - void *pointer, - const char *name, - PyCapsule_Destructor destructor); - -PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name); - -PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule); - -PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule); - -PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule); - -PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name); - -PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer); - -PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor); - -PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name); - -PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context); - -PyAPI_FUNC(void *) PyCapsule_Import( - const char *name, /* UTF-8 encoded string */ - int no_block); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_CAPSULE_H */ + +/* Capsule objects let you wrap a C "void *" pointer in a Python + object. They're a way of passing data through the Python interpreter + without creating your own custom type. + + Capsules are used for communication between extension modules. + They provide a way for an extension module to export a C interface + to other extension modules, so that extension modules can use the + Python import mechanism to link to one another. + + For more information, please see "c-api/capsule.html" in the + documentation. +*/ + +#ifndef Py_CAPSULE_H +#define Py_CAPSULE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyCapsule_Type; + +typedef void (*PyCapsule_Destructor)(PyObject *); + +#define PyCapsule_CheckExact(op) (Py_TYPE(op) == &PyCapsule_Type) + + +PyAPI_FUNC(PyObject *) PyCapsule_New( + void *pointer, + const char *name, + PyCapsule_Destructor destructor); + +PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name); + +PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule); + +PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule); + +PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule); + +PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name); + +PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer); + +PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor); + +PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name); + +PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context); + +PyAPI_FUNC(void *) PyCapsule_Import( + const char *name, /* UTF-8 encoded string */ + int no_block); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CAPSULE_H */ diff --git a/libs/nxpy/include/pyconfig.h b/libs/nxpy/include/pyconfig.h index 80031f63..25dd30cb 100644 --- a/libs/nxpy/include/pyconfig.h +++ b/libs/nxpy/include/pyconfig.h @@ -1,1543 +1,1543 @@ -/* pyconfig.h. Generated from pyconfig.h.in by configure. */ -/* pyconfig.h.in. Generated from configure.ac by autoheader. */ - - -#ifndef Py_PYCONFIG_H -#define Py_PYCONFIG_H - - - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Define for AIX if your compiler is a genuine IBM xlC/xlC_r and you want - support for AIX C++ shared extension modules. */ -/* #undef AIX_GENUINE_CPLUSPLUS */ - -/* Define if C doubles are 64-bit IEEE 754 binary format, stored in ARM - mixed-endian order (byte order 45670123) */ -/* #undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 */ - -/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the most - significant byte first */ -/* #undef DOUBLE_IS_BIG_ENDIAN_IEEE754 */ - -/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the - least significant byte first */ -/* #undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 */ - -/* Define if --enable-ipv6 is specified */ -/* #undef ENABLE_IPV6 */ - -/* Define if flock needs to be linked with bsd library. */ -/* #undef FLOCK_NEEDS_LIBBSD */ - -/* Define if getpgrp() must be called as getpgrp(0). */ -/* #undef GETPGRP_HAVE_ARG */ - -/* Define if gettimeofday() does not have second (timezone) argument This is - the case on Motorola V4 (R40V4.2) */ -/* #undef GETTIMEOFDAY_NO_TZ */ - -/* Define to 1 if you have the `accept4' function. */ -/* #define HAVE_ACCEPT4 1 */ // original: #define HAVE_ACCEPT4 1 - -/* Define to 1 if you have the `acosh' function. */ -#define HAVE_ACOSH 1 - -/* struct addrinfo (netdb.h) */ -#define HAVE_ADDRINFO 1 // original: /* #undef HAVE_ADDRINFO */ - -/* Define to 1 if you have the `alarm' function. */ -#undef HAVE_ALARM // original: #define HAVE_ALARM 1 - -/* Define if aligned memory access is required */ -#define HAVE_ALIGNED_REQUIRED 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ALLOCA_H 1 - -/* Define this if your time.h defines altzone. */ -/* #undef HAVE_ALTZONE */ - -/* Define to 1 if you have the `asinh' function. */ -#define HAVE_ASINH 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ASM_TYPES_H */ - -/* Define to 1 if you have the `atanh' function. */ -#define HAVE_ATANH 1 - -/* Define to 1 if you have the `bind_textdomain_codeset' function. */ -#define HAVE_BIND_TEXTDOMAIN_CODESET 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BLUETOOTH_BLUETOOTH_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BLUETOOTH_H */ - -/* Define if mbstowcs(NULL, "text", 0) does not return the number of wide - chars that would be converted. */ -/* #undef HAVE_BROKEN_MBSTOWCS */ - -/* Define if nice() returns success/failure instead of the new priority. */ -/* #undef HAVE_BROKEN_NICE */ - -/* Define if the system reports an invalid PIPE_BUF value. */ -/* #undef HAVE_BROKEN_PIPE_BUF */ - -/* Define if poll() sets errno on invalid file descriptors. */ -/* #undef HAVE_BROKEN_POLL */ - -/* Define if the Posix semaphores do not work on your system */ -/* #undef HAVE_BROKEN_POSIX_SEMAPHORES */ - -/* Define if pthread_sigmask() does not work on your system. */ -/* #undef HAVE_BROKEN_PTHREAD_SIGMASK */ - -/* define to 1 if your sem_getvalue is broken. */ -#define HAVE_BROKEN_SEM_GETVALUE 1 - -/* Define if `unsetenv` does not return an int. */ -/* #undef HAVE_BROKEN_UNSETENV */ - -/* Has builtin atomics */ -#define HAVE_BUILTIN_ATOMIC 1 - -/* Define this if you have the type _Bool. */ -#define HAVE_C99_BOOL 1 - -/* Define to 1 if you have the 'chflags' function. */ -/* #define HAVE_CHFLAGS 1 */ // original: #define HAVE_CHFLAGS 1 - -/* Define to 1 if you have the `chown' function. */ -/* #define HAVE_CHOWN 1 */ // original: #define HAVE_CHOWN 1 - -/* Define if you have the 'chroot' function. */ -/* #define HAVE_CHROOT 1 */ // original: #define HAVE_CHROOT 1 - -/* Define to 1 if you have the `clock' function. */ -#define HAVE_CLOCK 1 - -/* Define to 1 if you have the `clock_getres' function. */ -/* #define HAVE_CLOCK_GETRES 1 */ // original: #define HAVE_CLOCK_GETRES 1 - -/* Define to 1 if you have the `clock_gettime' function. */ -/* #define HAVE_CLOCK_GETTIME 1 */ // original: #define HAVE_CLOCK_GETTIME 1 - -/* Define if the C compiler supports computed gotos. */ -/* #undef HAVE_COMPUTED_GOTOS */ - -/* Define to 1 if you have the `confstr' function. */ -/* #define HAVE_CONFSTR 1 */ // original: #define HAVE_CONFSTR 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CONIO_H */ - -/* Define to 1 if you have the `copysign' function. */ -#define HAVE_COPYSIGN 1 - -/* Define to 1 if you have the `ctermid' function. */ -/* #define HAVE_CTERMID 1 */ // original: #define HAVE_CTERMID 1 - -/* Define if you have the 'ctermid_r' function. */ -/* #undef HAVE_CTERMID_R */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CURSES_H */ - -/* Define if you have the 'is_term_resized' function. */ -/* #undef HAVE_CURSES_IS_TERM_RESIZED */ - -/* Define if you have the 'resizeterm' function. */ -/* #undef HAVE_CURSES_RESIZETERM */ - -/* Define if you have the 'resize_term' function. */ -/* #undef HAVE_CURSES_RESIZE_TERM */ - -/* Define to 1 if you have the declaration of `isfinite', and to 0 if you - don't. */ -#define HAVE_DECL_ISFINITE 1 - -/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. - */ -#define HAVE_DECL_ISINF 1 - -/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. - */ -#define HAVE_DECL_ISNAN 1 - -/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. - */ -#undef HAVE_DECL_TZNAME // original: #define HAVE_DECL_TZNAME 1 - -/* Define to 1 if you have the device macros. */ -/* #define HAVE_DEVICE_MACROS 1 */ // original: #define HAVE_DEVICE_MACROS 1 - -/* Define to 1 if you have the /dev/ptc device file. */ -/* #undef HAVE_DEV_PTC */ - -/* Define to 1 if you have the /dev/ptmx device file. */ -/* #undef HAVE_DEV_PTMX */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DIRECT_H */ - -/* Define to 1 if the dirent structure has a d_type field */ -#define HAVE_DIRENT_D_TYPE 1 - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -#define HAVE_DIRENT_H 1 - -/* Define if you have the 'dirfd' function or macro. */ -/* #undef HAVE_DIRFD */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define to 1 if you have the `dlopen' function. */ -#undef HAVE_DLOPEN // original: #define HAVE_DLOPEN 1 - -/* Define to 1 if you have the `dup2' function. */ -#define HAVE_DUP2 1 - -/* Define to 1 if you have the `dup3' function. */ -/* #define HAVE_DUP3 1 */ // original: #define HAVE_DUP3 1 - -/* Defined when any dynamic module loading is enabled. */ -#undef HAVE_DYNAMIC_LOADING // original: #define HAVE_DYNAMIC_LOADING 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ENDIAN_H */ - -/* Define if you have the 'epoll' functions. */ -/* #undef HAVE_EPOLL */ - -/* Define if you have the 'epoll_create1' function. */ -/* #undef HAVE_EPOLL_CREATE1 */ - -/* Define to 1 if you have the `erf' function. */ -#define HAVE_ERF 1 - -/* Define to 1 if you have the `erfc' function. */ -#define HAVE_ERFC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the `execv' function. */ -#undef HAVE_EXECV // original: #define HAVE_EXECV 1 - -/* Define to 1 if you have the `expm1' function. */ -#define HAVE_EXPM1 1 - -/* Define to 1 if you have the `faccessat' function. */ -/* #define HAVE_FACCESSAT 1 */ // original: #define HAVE_FACCESSAT 1 - -/* Define if you have the 'fchdir' function. */ -/* #define HAVE_FCHDIR 1 */ // #define HAVE_FCHDIR 1 - -/* Define to 1 if you have the `fchmod' function. */ -#define HAVE_FCHMOD 1 - -/* Define to 1 if you have the `fchmodat' function. */ -/* #define HAVE_FCHMODAT 1 */ // original: #define HAVE_FCHMODAT 1 - -/* Define to 1 if you have the `fchown' function. */ -/* #define HAVE_FCHOWN 1 */ // original: #define HAVE_FCHOWN 1 - -/* Define to 1 if you have the `fchownat' function. */ -#define HAVE_FCHOWNAT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the 'fdatasync' function. */ -#undef HAVE_FDATASYNC // original: #define HAVE_FDATASYNC 1 - -/* Define to 1 if you have the `fdopendir' function. */ -/* #define HAVE_FDOPENDIR 1 */ // original: #define HAVE_FDOPENDIR 1 - -/* Define to 1 if you have the `fexecve' function. */ -#define HAVE_FEXECVE 1 - -/* Define to 1 if you have the `finite' function. */ -#define HAVE_FINITE 1 - -/* Define to 1 if you have the `flock' function. */ -#define HAVE_FLOCK 1 - -/* Define to 1 if you have the `fork' function. */ -#undef HAVE_FORK // original: #define HAVE_FORK 1 - -/* Define to 1 if you have the `forkpty' function. */ -#undef HAVE_FORKPTY // original: #define HAVE_FORKPTY 1 - -/* Define to 1 if you have the `fpathconf' function. */ -/* #define HAVE_FPATHCONF 1 */ // original: #define HAVE_FPATHCONF 1 - -/* Define to 1 if you have the `fseek64' function. */ -#define HAVE_FSEEK64 1 - -/* Define to 1 if you have the `fseeko' function. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `fstatat' function. */ -/* #define HAVE_FSTATAT 1 */ // original: #define HAVE_FSTATAT 1 - -/* Define to 1 if you have the `fstatvfs' function. */ -#define HAVE_FSTATVFS 1 - -/* Define if you have the 'fsync' function. */ -#define HAVE_FSYNC 1 - -/* Define to 1 if you have the `ftell64' function. */ -#define HAVE_FTELL64 1 - -/* Define to 1 if you have the `ftello' function. */ -#define HAVE_FTELLO 1 - -/* Define to 1 if you have the `ftime' function. */ -/* #define HAVE_FTIME 1 */ // original: #define HAVE_FTIME 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have the `futimens' function. */ -/* #define HAVE_FUTIMENS 1 */ // original: #define HAVE_FUTIMENS 1 - -/* Define to 1 if you have the `futimes' function. */ -/* #define HAVE_FUTIMES 1 */ // original: #define HAVE_FUTIMES 1 - -/* Define to 1 if you have the `futimesat' function. */ -/* #define HAVE_FUTIMESAT 1 */ // original: #define HAVE_FUTIMESAT 1 - -/* Define to 1 if you have the `gai_strerror' function. */ -#define HAVE_GAI_STRERROR 1 - -/* Define to 1 if you have the `gamma' function. */ -#define HAVE_GAMMA 1 - -/* Define if we can use gcc inline assembler to get and set mc68881 fpcr */ -/* #undef HAVE_GCC_ASM_FOR_MC68881 */ - -/* Define if we can use x64 gcc inline assembler */ -/* #undef HAVE_GCC_ASM_FOR_X64 */ - -/* Define if we can use gcc inline assembler to get and set x87 control word - */ -/* #undef HAVE_GCC_ASM_FOR_X87 */ - -/* Define if your compiler provides __uint128_t */ -#define HAVE_GCC_UINT128_T 1 - -/* Define if you have the getaddrinfo function. */ -#define HAVE_GETADDRINFO - -// TODO clarify what these are -#define SOCK_RAW 3 - -#define SOCK_SEQPACKET 5 - -#define IN_CLASSA_NSHIFT 24 - -/* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ -#undef HAVE_GETC_UNLOCKED // original: #define HAVE_GETC_UNLOCKED 1 - -/* Define to 1 if you have the `getentropy' function. */ -#undef HAVE_GETENTROPY // original: #define HAVE_GETENTROPY 1 - -/* Define to 1 if you have the `getgrouplist' function. */ -/* #define HAVE_GETGROUPLIST 1 */ // original: #define HAVE_GETGROUPLIST 1 - -/* Define to 1 if you have the `getgroups' function. */ -/* #define HAVE_GETGROUPS 1 */ // original: #define HAVE_GETGROUPS 1 - -/* Define to 1 if you have the `gethostbyname' function. */ -/* #undef HAVE_GETHOSTBYNAME */ - -/* Define this if you have some version of gethostbyname_r() */ -#define HAVE_GETHOSTBYNAME_R 1 - -/* Define this if you have the 3-arg version of gethostbyname_r(). */ -/* #undef HAVE_GETHOSTBYNAME_R_3_ARG */ - -/* Define this if you have the 5-arg version of gethostbyname_r(). */ -/* #undef HAVE_GETHOSTBYNAME_R_5_ARG */ - -/* Define this if you have the 6-arg version of gethostbyname_r(). */ -/* #undef HAVE_GETHOSTBYNAME_R_6_ARG */ - -/* Define to 1 if you have the `getitimer' function. */ -#undef HAVE_GETITIMER // original: #define HAVE_GETITIMER 1 - -/* Define to 1 if you have the `getloadavg' function. */ -/* #define HAVE_GETLOADAVG 1 */ // original: #define HAVE_GETLOADAVG 1 - -/* Define to 1 if you have the `getlogin' function. */ -/* #define HAVE_GETLOGIN 1 */ // original: #define HAVE_GETLOGIN 1 - -/* Define to 1 if you have the `getnameinfo' function. */ -#undef HAVE_GETNAMEINFO - -/* Define if you have the 'getpagesize' function. */ -#define HAVE_GETPAGESIZE 1 - -/* Define to 1 if you have the `getpeername' function. */ -#define HAVE_GETPEERNAME 1 - -/* Define to 1 if you have the `getpgid' function. */ -/* #define HAVE_GETPGID 1 */ // original: #define HAVE_GETPGID 1 - -/* Define to 1 if you have the `getpgrp' function. */ -/* #define HAVE_GETPGRP 1 */ // original: #define HAVE_GETPGRP 1 - -/* Define to 1 if you have the `getpid' function. */ -#define HAVE_GETPID 1 - -/* Define to 1 if you have the `getpriority' function. */ -/* #define HAVE_GETPRIORITY 1 */ // original: #define HAVE_GETPRIORITY 1 - -/* Define to 1 if you have the `getpwent' function. */ -#undef HAVE_GETPWENT // original: #define HAVE_GETPWENT 1 - -/* Define to 1 if the getrandom() function is available */ -/* #undef HAVE_GETRANDOM */ - -/* Define to 1 if the Linux getrandom() syscall is available */ -/* #undef HAVE_GETRANDOM_SYSCALL */ - -/* Define to 1 if you have the `getresgid' function. */ -/* #define HAVE_GETRESGID 1 */ // original: #define HAVE_GETRESGID 1 - -/* Define to 1 if you have the `getresuid' function. */ -/* #define HAVE_GETRESUID 1 */ // original: #define HAVE_GETRESUID 1 - -/* Define to 1 if you have the `getsid' function. */ -/* #define HAVE_GETSID 1 */ // original: #define HAVE_GETSID 1 - -/* Define to 1 if you have the `getspent' function. */ -#define HAVE_GETSPENT 1 - -/* Define to 1 if you have the `getspnam' function. */ -#define HAVE_GETSPNAM 1 - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the `getwd' function. */ -#define HAVE_GETWD 1 - -/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and - bcopy. */ -/* #undef HAVE_GLIBC_MEMMOVE_BUG */ - -/* Define to 1 if you have the header file. */ -#define HAVE_GRP_H 1 - -/* Define if you have the 'hstrerror' function. */ -/* #undef HAVE_HSTRERROR */ - -/* Define this if you have le64toh() */ -#define HAVE_HTOLE64 1 - -/* Define to 1 if you have the `hypot' function. */ -#define HAVE_HYPOT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_IEEEFP_H 1 - -/* Define to 1 if you have the `if_nameindex' function. */ -/* #define HAVE_IF_NAMEINDEX 1 */ // original: #define HAVE_IF_NAMEINDEX 1 - -/* Define if you have the 'inet_aton' function. */ -/* #define HAVE_INET_ATON 1 */ // original: #define HAVE_INET_ATON 1 - -/* Define if you have the 'inet_pton' function. */ -#define HAVE_INET_PTON 1 - -/* Define to 1 if you have the `initgroups' function. */ -/* #define HAVE_INITGROUPS 1 */ // original: #define HAVE_INITGROUPS 1 - -/* Define if your compiler provides int32_t. */ -#define HAVE_INT32_T 1 - -/* Define if your compiler provides int64_t. */ -#define HAVE_INT64_T 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IO_H */ - -/* Define if gcc has the ipa-pure-const bug. */ -/* #undef HAVE_IPA_PURE_CONST_BUG */ - -/* Define to 1 if you have the `kill' function. */ -#undef HAVE_KILL // original: #define HAVE_KILL 1 - -/* Define to 1 if you have the `killpg' function. */ -#undef HAVE_KILLPG // original: #define HAVE_KILLPG 1 - -/* Define if you have the 'kqueue' functions. */ -/* #undef HAVE_KQUEUE */ - -/* Define to 1 if you have the header file. */ -#define HAVE_LANGINFO_H 1 - -/* Defined to enable large file support when an off_t is bigger than a long - and long long is available and at least as big as an off_t. You may need to - add some flags for configuration and compilation to enable this mode. (For - Solaris and Linux, the necessary defines are already defined.) */ -/* #undef HAVE_LARGEFILE_SUPPORT */ - -/* Define to 1 if you have the 'lchflags' function. */ -/* #define HAVE_LCHFLAGS 1 */ // original: #define HAVE_LCHFLAGS 1 - -/* Define to 1 if you have the `lchmod' function. */ -/* #define HAVE_LCHMOD 1 */ // original: #define HAVE_LCHMOD 1 - -/* Define to 1 if you have the `lchown' function. */ -/* #define HAVE_LCHOWN 1 */ // original: #define HAVE_LCHOWN 1 - -/* Define to 1 if you have the `lgamma' function. */ -#define HAVE_LGAMMA 1 - -/* Define to 1 if you have the `dl' library (-ldl). */ -/* #undef HAVE_LIBDL */ - -/* Define to 1 if you have the `dld' library (-ldld). */ -/* #undef HAVE_LIBDLD */ - -/* Define to 1 if you have the `ieee' library (-lieee). */ -/* #undef HAVE_LIBIEEE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBINTL_H */ - -/* Define if you have the readline library (-lreadline). */ -/* #undef HAVE_LIBREADLINE */ - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `sendfile' library (-lsendfile). */ -/* #undef HAVE_LIBSENDFILE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIBUTIL_H */ - -/* Define if you have the 'link' function. */ -#define HAVE_LINK 1 - -/* Define to 1 if you have the `linkat' function. */ -/* #define HAVE_LINKAT 1 */ // original: #define HAVE_LINKAT 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_CAN_BCM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_CAN_H */ - -/* Define if compiling using Linux 3.6 or later. */ -/* #undef HAVE_LINUX_CAN_RAW_FD_FRAMES */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_CAN_RAW_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_NETLINK_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_RANDOM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINUX_TIPC_H */ - -/* Define to 1 if you have the `lockf' function. */ -/* #define HAVE_LOCKF 1 */ // original: #define HAVE_LOCKF 1 - -/* Define to 1 if you have the `log1p' function. */ -#define HAVE_LOG1P 1 - -/* Define to 1 if you have the `log2' function. */ -#define HAVE_LOG2 1 - -/* Define this if you have the type long double. */ -#define HAVE_LONG_DOUBLE 1 - -/* Define this if you have the type long long. */ -#define HAVE_LONG_LONG 1 - -/* Define to 1 if you have the `lstat' function. */ -#define HAVE_LSTAT 1 /* We don't really have lstat, but sed replaces it with stat */ - -/* Define to 1 if you have the `lutimes' function. */ -/* #define HAVE_LUTIMES 1 */ // original: #define HAVE_LUTIMES 1 - -/* Define this if you have the makedev macro. */ -/* #define HAVE_MAKEDEV 1 */ // original: #define HAVE_MAKEDEV 1 - -/* Define to 1 if you have the `mbrtowc' function. */ -#define HAVE_MBRTOWC 1 - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memrchr' function. */ -#define HAVE_MEMRCHR 1 - -/* Define to 1 if you have the `mkdirat' function. */ -/* #define HAVE_MKDIRAT 1 */ // #define HAVE_MKDIRAT 1 - -/* Define to 1 if you have the `mkfifo' function. */ -/* #define HAVE_MKFIFO 1 */ // original: #define HAVE_MKFIFO 1 - -/* Define to 1 if you have the `mkfifoat' function. */ -#define HAVE_MKFIFOAT 1 - -/* Define to 1 if you have the `mknod' function. */ -/* #define HAVE_MKNOD 1 */ // original: #define HAVE_MKNOD 1 - -/* Define to 1 if you have the `mknodat' function. */ -#define HAVE_MKNODAT 1 - -/* Define to 1 if you have the `mktime' function. */ -#define HAVE_MKTIME 1 - -/* Define to 1 if you have the `mmap' function. */ -#undef HAVE_MMAP // original: #define HAVE_MMAP 1 - -/* Define to 1 if you have the `mremap' function. */ -#define HAVE_MREMAP 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NCURSES_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETPACKET_PACKET_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_NET_IF_H 1 - -/* Define to 1 if you have the `nice' function. */ -/* #define HAVE_NICE 1 */ // original: #define HAVE_NICE 1 - -/* Define to 1 if you have the `openat' function. */ -/* #define HAVE_OPENAT 1 */ // original: #define HAVE_OPENAT 1 - -/* Define to 1 if you have the `openpty' function. */ -#undef HAVE_OPENPTY // original: #define HAVE_OPENPTY 1 - -/* Define if compiling using MacOS X 10.5 SDK or later. */ -/* #undef HAVE_OSX105_SDK */ - -/* Define to 1 if you have the `pathconf' function. */ -/* #define HAVE_PATHCONF 1 */ // original: #define HAVE_PATHCONF 1 - -/* Define to 1 if you have the `pause' function. */ -#undef HAVE_PAUSE // original: #define HAVE_PAUSE 1 - -/* Define to 1 if you have the `pipe2' function. */ -/* #define HAVE_PIPE2 1 */ // original: #define HAVE_PIPE2 1 - -/* Define to 1 if you have the `plock' function. */ -/* #define HAVE_PLOCK 1 */ // original: #define HAVE_PLOCK 1 - -/* Define to 1 if you have the `poll' function. */ -/* #define HAVE_POLL 1 */ // original: #define HAVE_POLL 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_POLL_H */ // original: #define HAVE_POLL_H 1 - -/* Define to 1 if you have the `posix_fadvise' function. */ -/* #define HAVE_POSIX_FADVISE 1 */ // original: #define HAVE_POSIX_FADVISE 1 - -/* Define to 1 if you have the `posix_fallocate' function. */ -/* #define HAVE_POSIX_FALLOCATE 1 */ // original: #define HAVE_POSIX_FALLOCATE 1 - -/* Define to 1 if you have the `pread' function. */ -/* #define HAVE_PREAD 1 */ // original: #define HAVE_PREAD 1 - -/* Define if you have the 'prlimit' functions. */ -/* #undef HAVE_PRLIMIT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PROCESS_H */ - -/* Define if your compiler supports function prototype */ -#define HAVE_PROTOTYPES 1 - -/* Define to 1 if you have the `pthread_atfork' function. */ -/* #undef HAVE_PTHREAD_ATFORK */ - -/* Defined for Solaris 2.6 bug in pthread header. */ -/* #undef HAVE_PTHREAD_DESTRUCTOR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PTHREAD_H 1 - -/* Define to 1 if you have the `pthread_init' function. */ -#define HAVE_PTHREAD_INIT 1 - -/* Define to 1 if you have the `pthread_kill' function. */ -#define HAVE_PTHREAD_KILL 1 - -/* Define to 1 if you have the `pthread_sigmask' function. */ -/* #undef HAVE_PTHREAD_SIGMASK */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PTY_H */ - -/* Define to 1 if you have the `putenv' function. */ -#define HAVE_PUTENV 1 - -/* Define to 1 if you have the `pwrite' function. */ -/* #define HAVE_PWRITE 1 */ // original: #define HAVE_PWRITE 1 - -/* Define to 1 if you have the `readlink' function. */ -#undef HAVE_READLINK // original: #define HAVE_READLINK 1 - -/* Define to 1 if you have the `readlinkat' function. */ -#define HAVE_READLINKAT 1 - -/* Define to 1 if you have the `readv' function. */ -/* #define HAVE_READV 1 */ // original: #define HAVE_READV 1 - -/* Define to 1 if you have the `realpath' function. */ -#define HAVE_REALPATH 1 - -/* Define to 1 if you have the `renameat' function. */ -/* #define HAVE_RENAMEAT 1 */ // original: #define HAVE_RENAMEAT 1 - -/* Define if readline supports append_history */ -/* #undef HAVE_RL_APPEND_HISTORY */ - -/* Define if you have readline 2.1 */ -/* #undef HAVE_RL_CALLBACK */ - -/* Define if you can turn off readline's signal handling. */ -/* #undef HAVE_RL_CATCH_SIGNAL */ - -/* Define if you have readline 2.2 */ -/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */ - -/* Define if you have readline 4.0 */ -/* #undef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK */ - -/* Define if you have readline 4.2 */ -/* #undef HAVE_RL_COMPLETION_MATCHES */ - -/* Define if you have rl_completion_suppress_append */ -/* #undef HAVE_RL_COMPLETION_SUPPRESS_APPEND */ - -/* Define if you have readline 4.0 */ -/* #undef HAVE_RL_PRE_INPUT_HOOK */ - -/* Define if you have readline 4.0 */ -/* #undef HAVE_RL_RESIZE_TERMINAL */ - -/* Define to 1 if you have the `round' function. */ -#define HAVE_ROUND 1 - -/* Define to 1 if you have the `sched_get_priority_max' function. */ -/* #define HAVE_SCHED_GET_PRIORITY_MAX 1 */ // original: #define HAVE_SCHED_GET_PRIORITY_MAX 1 - -/* Define to 1 if you have the header file. */ -/* #define HAVE_SCHED_H 1 */ // original: #define HAVE_SCHED_H 1 - -/* Define to 1 if you have the `sched_rr_get_interval' function. */ -/* #define HAVE_SCHED_RR_GET_INTERVAL 1 */ // original: #define HAVE_SCHED_RR_GET_INTERVAL 1 - -/* Define to 1 if you have the `sched_setaffinity' function. */ -#define HAVE_SCHED_SETAFFINITY 1 - -/* Define to 1 if you have the `sched_setparam' function. */ -/* #define HAVE_SCHED_SETPARAM 1 */ //original: #define HAVE_SCHED_SETPARAM 1 - -/* Define to 1 if you have the `sched_setscheduler' function. */ -/* #define HAVE_SCHED_SETSCHEDULER 1 */ // original: #define HAVE_SCHED_SETSCHEDULER 1 - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `sem_getvalue' function. */ -#define HAVE_SEM_GETVALUE 1 - -/* Define to 1 if you have the `sem_open' function. */ -#define HAVE_SEM_OPEN 1 - -/* Define to 1 if you have the `sem_timedwait' function. */ -#define HAVE_SEM_TIMEDWAIT 1 - -/* Define to 1 if you have the `sem_unlink' function. */ -#define HAVE_SEM_UNLINK 1 - -/* Define to 1 if you have the `sendfile' function. */ -/* #define HAVE_SENDFILE 1 */ // original: #define HAVE_SENDFILE 1 - -/* Define to 1 if you have the `setegid' function. */ -/* #define HAVE_SETEGID 1 */ // original: #define HAVE_SETEGID 1 - -/* Define to 1 if you have the `seteuid' function. */ -/* #define HAVE_SETEUID 1 */ // original: #define HAVE_SETEUID 1 - -/* Define to 1 if you have the `setgid' function. */ -/* #define HAVE_SETGID 1 */ // original: #define HAVE_SETGID 1 - -/* Define if you have the 'setgroups' function. */ -/* #define HAVE_SETGROUPS 1 */ // original: #define HAVE_SETGROUPS 1 - -/* Define to 1 if you have the `sethostname' function. */ -/* #define HAVE_SETHOSTNAME 1 */ // original: #define HAVE_SETHOSTNAME 1 - -/* Define to 1 if you have the `setitimer' function. */ -/* #define HAVE_SETITIMER 1 */ // original: #define HAVE_SETITIMER 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `setpgid' function. */ -/* #define HAVE_SETPGID 1 */ // original: #define HAVE_SETPGID 1 - -/* Define to 1 if you have the `setpgrp' function. */ -/* #define HAVE_SETPGRP 1 */ // original: #define HAVE_SETPGRP 1 - -/* Define to 1 if you have the `setpriority' function. */ -/* #define HAVE_SETPRIORITY 1 */ // original: #define HAVE_SETPRIORITY 1 - -/* Define to 1 if you have the `setregid' function. */ -/* #define HAVE_SETREGID 1 */ // original: #define HAVE_SETREGID 1 - -/* Define to 1 if you have the `setresgid' function. */ -/* #define HAVE_SETRESGID 1 */ // original: #define HAVE_SETRESGID 1 - -/* Define to 1 if you have the `setresuid' function. */ -/* #define HAVE_SETRESUID 1 */ // original: #define HAVE_SETRESUID 1 - -/* Define to 1 if you have the `setreuid' function. */ -/* #define HAVE_SETREUID 1 */ // original: #define HAVE_SETREUID 1 - -/* Define to 1 if you have the `setsid' function. */ -/* #define HAVE_SETSID 1 */ // original: #define HAVE_SETSID 1 - -/* Define to 1 if you have the `setuid' function. */ -/* #define HAVE_SETUID 1 */ // original: #define HAVE_SETUID 1 - -/* Define to 1 if you have the `setvbuf' function. */ -#define HAVE_SETVBUF 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SHADOW_H */ - -/* Define to 1 if you have the `sigaction' function. */ -#undef HAVE_SIGACTION // original: #define HAVE_SIGACTION 1 - -/* Define to 1 if you have the `sigaltstack' function. */ -/* #define HAVE_SIGALTSTACK 1 */ // original: #define HAVE_SIGALTSTACK 1 - -/* Define to 1 if you have the `siginterrupt' function. */ -#undef HAVE_SIGINTERRUPT // original: #define HAVE_SIGINTERRUPT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the `sigpending' function. */ -#define HAVE_SIGPENDING 1 - -/* Define to 1 if you have the `sigrelse' function. */ -#define HAVE_SIGRELSE 1 - -/* Define to 1 if you have the `sigtimedwait' function. */ -#define HAVE_SIGTIMEDWAIT 1 - -/* Define to 1 if you have the `sigwait' function. */ -#define HAVE_SIGWAIT 1 - -/* Define to 1 if you have the `sigwaitinfo' function. */ -#define HAVE_SIGWAITINFO 1 - -/* Define to 1 if you have the `snprintf' function. */ -#define HAVE_SNPRINTF 1 - -/* Define if sockaddr has sa_len member */ -/* #define HAVE_SOCKADDR_SA_LEN 1 */ // original: #define HAVE_SOCKADDR_SA_LEN 1 - -/* struct sockaddr_storage (sys/socket.h) */ -#define HAVE_SOCKADDR_STORAGE 1 - -/* Define if you have the 'socketpair' function. */ -/* #define HAVE_SOCKETPAIR 1 */ // original: #define HAVE_SOCKETPAIR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SPAWN_H 1 - -/* Define if your compiler provides ssize_t */ -#define HAVE_SSIZE_T 1 - -/* Define to 1 if you have the `statvfs' function. */ -#undef HAVE_STATVFS // original: #define HAVE_STATVFS 1 - -/* Define if you have struct stat.st_mtim.tv_nsec */ -/* #undef HAVE_STAT_TV_NSEC */ - -/* Define if you have struct stat.st_mtimensec */ -/* #undef HAVE_STAT_TV_NSEC2 */ - -/* Define if your compiler supports variable length function prototypes (e.g. - void fprintf(FILE *, char *, ...);) *and* */ -#define HAVE_STDARG_PROTOTYPES 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Has stdatomic.h, atomic_int and _Atomic void* types work */ -#define HAVE_STD_ATOMIC 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strlcpy' function. */ -#define HAVE_STRLCPY 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STROPTS_H */ - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ - -/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 - -/* Define to 1 if `st_blocks' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_BLOCKS 1 - -/* Define to 1 if `st_flags' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ - -/* Define to 1 if `st_gen' is a member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_GEN */ - -/* Define to 1 if `st_rdev' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_RDEV 1 - -/* Define to 1 if `tm_zone' is a member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM_TM_ZONE */ - -/* Define if you have the 'symlink' function. */ -#undef HAVE_SYMLINK // original: #define HAVE_SYMLINK 1 - -/* Define to 1 if you have the `symlinkat' function. */ -#define HAVE_SYMLINKAT 1 - -/* Define to 1 if you have the `sync' function. */ -/* #define HAVE_SYNC 1 */ // original: #define HAVE_SYNC 1 - -/* Define to 1 if you have the `sysconf' function. */ -/* #define HAVE_SYSCONF 1 */ // original: #define HAVE_SYSCONF 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYSEXITS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_AUDIOIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_BSDTTY_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_DEVPOLL_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ENDIAN_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EPOLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_EVENT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_FILE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_KERN_CONTROL_H */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_LOADAVG_H // original: /* #undef HAVE_SYS_LOADAVG_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_LOCK_H 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MKDEV_H // original: /* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MODEM_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_RANDOM_H */ - -/* Define to 1 if you have the header file. */ -/* #define HAVE_SYS_RESOURCE_H 1 */ // original: #define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SENDFILE_H */ - -/* Define to 1 if you have the header file. */ -/* #define HAVE_SYS_SOCKET_H 1 */ // original: #define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STATVFS_H // original: #define HAVE_SYS_STATVFS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SYSCALL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SYS_DOMAIN_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TERMIO_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIMES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UN_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UTSNAME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_WAIT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the `tcgetpgrp' function. */ -/* #define HAVE_TCGETPGRP 1 */ // original: #define HAVE_TCGETPGRP 1 - -/* Define to 1 if you have the `tcsetpgrp' function. */ -/* #define HAVE_TCSETPGRP 1 */ // original: #define HAVE_TCSETPGRP 1 - -/* Define to 1 if you have the `tempnam' function. */ -#define HAVE_TEMPNAM 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIOS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERM_H */ - -/* Define to 1 if you have the `tgamma' function. */ -#define HAVE_TGAMMA 1 - -/* Define to 1 if you have the `timegm' function. */ -#define HAVE_TIMEGM 1 - -/* Define to 1 if you have the `times' function. */ -#define HAVE_TIMES 1 - -/* Define to 1 if you have the `tmpfile' function. */ -#define HAVE_TMPFILE 1 - -/* Define to 1 if you have the `tmpnam' function. */ -#define HAVE_TMPNAM 1 - -/* Define to 1 if you have the `tmpnam_r' function. */ -#define HAVE_TMPNAM_R 1 - -/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use - `HAVE_STRUCT_TM_TM_ZONE' instead. */ -/* #undef HAVE_TM_ZONE */ - -/* Define to 1 if you have the `truncate' function. */ -#define HAVE_TRUNCATE 1 - -/* Define to 1 if you don't have `tm_zone' but do have the external array - `tzname'. */ -#undef HAVE_TZNAME // original: #define HAVE_TZNAME 1 - -/* Define this if you have tcl and TCL_UTF_MAX==6 */ -/* #undef HAVE_UCS4_TCL */ - -/* Define if your compiler provides uint32_t. */ -#define HAVE_UINT32_T 1 - -/* Define if your compiler provides uint64_t. */ -#define HAVE_UINT64_T 1 - -/* Define to 1 if the system has the type `uintptr_t'. */ -#define HAVE_UINTPTR_T 1 - -/* Define to 1 if you have the `uname' function. */ -/* #define HAVE_UNAME 1 */ // original: #define HAVE_UNAME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `unlinkat' function. */ -/* #define HAVE_UNLINKAT 1 */ // original: #define HAVE_UNLINKAT 1 - -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - -/* Define if you have a useable wchar_t type defined in wchar.h; useable means - wchar_t must be an unsigned type with at least 16 bits. (see - Include/unicodeobject.h). */ -/* #undef HAVE_USABLE_WCHAR_T */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UTIL_H */ - -/* Define to 1 if you have the `utimensat' function. */ -/* #define HAVE_UTIMENSAT 1 */ // original: #define HAVE_UTIMENSAT 1 - -/* Define to 1 if you have the `utimes' function. */ -/* #define HAVE_UTIMES 1 */ // original: #define HAVE_UTIMES 1 - -/* Define to 1 if you have the header file. */ -/* #define HAVE_UTIME_H 1 */ // original: #define HAVE_UTIME_H 1 - -/* Define to 1 if you have the `wait3' function. */ -/* #define HAVE_WAIT3 1 */ // original: #define HAVE_WAIT3 1 - -/* Define to 1 if you have the `wait4' function. */ -/* #define HAVE_WAIT4 1 */ // original: #define HAVE_WAIT4 1 - -/* Define to 1 if you have the `waitid' function. */ -/* #define HAVE_WAITID 1 */ // original: #define HAVE_WAITID 1 - -/* Define to 1 if you have the `waitpid' function. */ -/* #define HAVE_WAITPID 1 */ // original: #define HAVE_WAITPID 1 - -/* Define if the compiler provides a wchar.h header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if you have the `wcscoll' function. */ -#define HAVE_WCSCOLL 1 - -/* Define to 1 if you have the `wcsftime' function. */ -#define HAVE_WCSFTIME 1 - -/* Define to 1 if you have the `wcsxfrm' function. */ -#define HAVE_WCSXFRM 1 - -/* Define to 1 if you have the `wmemcmp' function. */ -#define HAVE_WMEMCMP 1 - -/* Define if tzset() actually switches the local timezone in a meaningful way. - */ -/* #undef HAVE_WORKING_TZSET */ - -/* Define to 1 if you have the `writev' function. */ -/* #define HAVE_WRITEV 1 */ // orignal: #define HAVE_WRITEV 1 - -/* Define if the zlib library has inflateCopy */ -/* #undef HAVE_ZLIB_COPY */ - -/* Define to 1 if you have the `_getpty' function. */ -/* #define HAVE__GETPTY 1 */ // original: #define HAVE__GETPTY 1 - -/* Define if log1p(-0.) is 0. rather than -0. */ -/* #undef LOG1P_DROPS_ZERO_SIGN */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -#undef MAJOR_IN_MKDEV // original: /* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define if mvwdelch in curses.h is an expression. */ -/* #undef MVWDELCH_IS_EXPRESSION */ - -/* Define to the address where bug reports for this package should be sent. */ -/* #undef PACKAGE_BUGREPORT */ - -/* Define to the full name of this package. */ -/* #undef PACKAGE_NAME */ - -/* Define to the full name and version of this package. */ -/* #undef PACKAGE_STRING */ - -/* Define to the one symbol short name of this package. */ -/* #undef PACKAGE_TARNAME */ - -/* Define to the home page for this package. */ -/* #undef PACKAGE_URL */ - -/* Define to the version of this package. */ -/* #undef PACKAGE_VERSION */ - -/* Define if POSIX semaphores aren't enabled on your system */ -/* #undef POSIX_SEMAPHORES_NOT_ENABLED */ - -/* Defined if PTHREAD_SCOPE_SYSTEM supported. */ -/* #undef PTHREAD_SYSTEM_SCHED_SUPPORTED */ - -/* Define as the preferred size in bits of long digits */ -/* #undef PYLONG_BITS_IN_DIGIT */ - -/* Define to printf format modifier for long long type */ -#define PY_FORMAT_LONG_LONG "ll" // original: #undef PY_FORMAT_LONG_LONG - -/* Define to printf format modifier for Py_ssize_t */ -#define PY_FORMAT_SIZE_T "z" - -/* Define if you want to build an interpreter with many run-time checks. */ -/* #undef Py_DEBUG */ - -/* Defined if Python is built as a shared library. */ -/* #undef Py_ENABLE_SHARED */ - -/* Define hash algorithm for str, bytes and memoryview. SipHash24: 1, FNV: 2, - externally defined: 0 */ -/* #undef Py_HASH_ALGORITHM */ - -/* assume C89 semantics that RETSIGTYPE is always void */ -#define RETSIGTYPE void - -/* Define if setpgrp() must be called as setpgrp(0, 0). */ -/* #undef SETPGRP_HAVE_ARG */ - -/* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ -/* #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS */ - -/* The size of `double', as computed by sizeof. */ -#define SIZEOF_DOUBLE 8 - -/* The size of `float', as computed by sizeof. */ -#define SIZEOF_FLOAT 4 - -/* The size of `fpos_t', as computed by sizeof. */ -#define SIZEOF_FPOS_T 8 - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 8 - -/* The size of `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 16 - -/* The size of `long long', as computed by sizeof. */ -#define SIZEOF_LONG_LONG 8 - -/* The size of `off_t', as computed by sizeof. */ -#define SIZEOF_OFF_T 8 - -/* The size of `pid_t', as computed by sizeof. */ -#define SIZEOF_PID_T 4 - -/* The size of `pthread_t', as computed by sizeof. */ -#define SIZEOF_PTHREAD_T 4 - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* The size of `size_t', as computed by sizeof. */ -#define SIZEOF_SIZE_T 8 - -/* The size of `time_t', as computed by sizeof. */ -#define SIZEOF_TIME_T 8 - -/* The size of `uintptr_t', as computed by sizeof. */ -#define SIZEOF_UINTPTR_T 8 - -/* The size of `void *', as computed by sizeof. */ -#define SIZEOF_VOID_P 8 - -/* The size of `wchar_t', as computed by sizeof. */ -#define SIZEOF_WCHAR_T 4 - -/* The size of `_Bool', as computed by sizeof. */ -#define SIZEOF__BOOL 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and - (which you can't on SCO ODT 3.0). */ -#define SYS_SELECT_WITH_SYS_TIME 1 - -/* Define if tanh(-0.) is -0., or if platform doesn't have signed zeros */ -/* #undef TANH_PRESERVES_ZERO_SIGN */ - -/* Library needed by timemodule.c: librt may be needed for clock_gettime() */ -/* #undef TIMEMODULE_LIB */ - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to 1 if your declares `struct tm'. */ -/* #undef TM_IN_SYS_TIME */ - -/* Define if you want to use computed gotos in ceval.c. */ -/* #undef USE_COMPUTED_GOTOS */ - -/* Define to use the C99 inline keyword. */ -#define USE_INLINE 1 - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif - - -/* Define if a va_list is an array of some kind */ -/* #undef VA_LIST_IS_ARRAY */ - -/* Define if you want SIGFPE handled (see Include/pyfpe.h). */ -/* #undef WANT_SIGFPE_HANDLER */ - -/* Define if WINDOW in curses.h offers a field _flags. */ -/* #undef WINDOW_HAS_FLAGS */ - -/* Define if you want documentation strings in extension modules */ -/* #undef WITH_DOC_STRINGS */ - -/* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic - linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). - Dyld is necessary to support frameworks. */ -/* #undef WITH_DYLD */ - -/* Define to 1 if libintl is needed for locale functions. */ -/* #undef WITH_LIBINTL */ - -/* Define if you want to produce an OpenStep/Rhapsody framework (shared - library plus accessory files). */ -/* #undef WITH_NEXT_FRAMEWORK */ - -/* Define if you want to compile in Python-specific mallocs */ -#define WITH_PYMALLOC 1 - -/* Define if you want to compile in rudimentary thread support */ -#define WITH_THREAD - -/* Define to profile with the Pentium timestamp counter */ -/* #undef WITH_TSC */ - -/* Define if you want pymalloc to be disabled when running under valgrind */ -/* #undef WITH_VALGRIND */ - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -/* Define if arithmetic is subject to x87-style double rounding issue */ -/* #undef X87_DOUBLE_ROUNDING */ - -/* Define on OpenBSD to activate all library features */ -/* #undef _BSD_SOURCE */ - -/* Define on Irix to enable u_int */ -#define _BSD_TYPES 1 - -/* Define on Darwin to activate all library features */ -#define _DARWIN_C_SOURCE 1 - -/* This must be set to 64 on some systems to enable large file support. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define on Linux to activate all library features */ -#define _GNU_SOURCE 1 - -/* Define to include mbstate_t for mbrtowc */ -/* #undef _INCLUDE__STDC_A1_SOURCE */ - -/* This must be defined on some systems to enable large file support. */ -/* #undef _LARGEFILE_SOURCE */ - -/* This must be defined on AIX systems to enable large file support. */ -/* #undef _LARGE_FILES */ - -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define on NetBSD to activate all library features */ -#define _NETBSD_SOURCE 1 - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to activate features from IEEE Stds 1003.1-2008 */ -#define _POSIX_C_SOURCE 200809L - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define if you have POSIX threads, and your system does not define that. */ -/* #undef _POSIX_THREADS */ - -/* Define to force use of thread-safe errno, h_errno, and other functions */ -/* #undef _REENTRANT */ - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT32_T */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define to the level of X/Open that your system supports */ -#define _XOPEN_SOURCE 700 - -/* Define to activate Unix95-and-earlier features */ -#define _XOPEN_SOURCE_EXTENDED 1 - -/* Define on FreeBSD to activate all library features */ -#define __BSD_VISIBLE 1 - -/* Define to 1 if type `char' is unsigned and you are not using gcc. */ -#ifndef __CHAR_UNSIGNED__ -/* # undef __CHAR_UNSIGNED__ */ -#endif - -/* Define to 'long' if doesn't define. */ -/* #undef clock_t */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `int' if doesn't define. */ -/* #undef gid_t */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to the type of a signed integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int32_t */ - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int64_t */ - -/* Define to `int' if does not define. */ -/* #undef mode_t */ - -/* Define to `long int' if does not define. */ -/* #undef off_t */ - -/* Define to `int' if does not define. */ -/* #undef pid_t */ - -/* Define to empty if the keyword does not work. */ -/* #undef signed */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to `int' if does not define. */ -/* #define socklen_t int */ - -/* Define to `int' if doesn't define. */ -/* #undef uid_t */ - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint32_t */ - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -/* #undef uint64_t */ - -/* Define to empty if the keyword does not work. */ -/* #undef volatile */ - - -/* Define the macros needed if on a UnixWare 7.x system. */ -#if defined(__USLC__) && defined(__SCO_VERSION__) -#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ -#endif - -#endif /*Py_PYCONFIG_H*/ - +/* pyconfig.h. Generated from pyconfig.h.in by configure. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ + + +#ifndef Py_PYCONFIG_H +#define Py_PYCONFIG_H + + + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define for AIX if your compiler is a genuine IBM xlC/xlC_r and you want + support for AIX C++ shared extension modules. */ +/* #undef AIX_GENUINE_CPLUSPLUS */ + +/* Define if C doubles are 64-bit IEEE 754 binary format, stored in ARM + mixed-endian order (byte order 45670123) */ +/* #undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 */ + +/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the most + significant byte first */ +/* #undef DOUBLE_IS_BIG_ENDIAN_IEEE754 */ + +/* Define if C doubles are 64-bit IEEE 754 binary format, stored with the + least significant byte first */ +/* #undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 */ + +/* Define if --enable-ipv6 is specified */ +/* #undef ENABLE_IPV6 */ + +/* Define if flock needs to be linked with bsd library. */ +/* #undef FLOCK_NEEDS_LIBBSD */ + +/* Define if getpgrp() must be called as getpgrp(0). */ +/* #undef GETPGRP_HAVE_ARG */ + +/* Define if gettimeofday() does not have second (timezone) argument This is + the case on Motorola V4 (R40V4.2) */ +/* #undef GETTIMEOFDAY_NO_TZ */ + +/* Define to 1 if you have the `accept4' function. */ +/* #define HAVE_ACCEPT4 1 */ // original: #define HAVE_ACCEPT4 1 + +/* Define to 1 if you have the `acosh' function. */ +#define HAVE_ACOSH 1 + +/* struct addrinfo (netdb.h) */ +#define HAVE_ADDRINFO 1 // original: /* #undef HAVE_ADDRINFO */ + +/* Define to 1 if you have the `alarm' function. */ +#undef HAVE_ALARM // original: #define HAVE_ALARM 1 + +/* Define if aligned memory access is required */ +#define HAVE_ALIGNED_REQUIRED 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define this if your time.h defines altzone. */ +/* #undef HAVE_ALTZONE */ + +/* Define to 1 if you have the `asinh' function. */ +#define HAVE_ASINH 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ASM_TYPES_H */ + +/* Define to 1 if you have the `atanh' function. */ +#define HAVE_ATANH 1 + +/* Define to 1 if you have the `bind_textdomain_codeset' function. */ +#define HAVE_BIND_TEXTDOMAIN_CODESET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BLUETOOTH_BLUETOOTH_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BLUETOOTH_H */ + +/* Define if mbstowcs(NULL, "text", 0) does not return the number of wide + chars that would be converted. */ +/* #undef HAVE_BROKEN_MBSTOWCS */ + +/* Define if nice() returns success/failure instead of the new priority. */ +/* #undef HAVE_BROKEN_NICE */ + +/* Define if the system reports an invalid PIPE_BUF value. */ +/* #undef HAVE_BROKEN_PIPE_BUF */ + +/* Define if poll() sets errno on invalid file descriptors. */ +/* #undef HAVE_BROKEN_POLL */ + +/* Define if the Posix semaphores do not work on your system */ +/* #undef HAVE_BROKEN_POSIX_SEMAPHORES */ + +/* Define if pthread_sigmask() does not work on your system. */ +/* #undef HAVE_BROKEN_PTHREAD_SIGMASK */ + +/* define to 1 if your sem_getvalue is broken. */ +#define HAVE_BROKEN_SEM_GETVALUE 1 + +/* Define if `unsetenv` does not return an int. */ +/* #undef HAVE_BROKEN_UNSETENV */ + +/* Has builtin atomics */ +#define HAVE_BUILTIN_ATOMIC 1 + +/* Define this if you have the type _Bool. */ +#define HAVE_C99_BOOL 1 + +/* Define to 1 if you have the 'chflags' function. */ +/* #define HAVE_CHFLAGS 1 */ // original: #define HAVE_CHFLAGS 1 + +/* Define to 1 if you have the `chown' function. */ +/* #define HAVE_CHOWN 1 */ // original: #define HAVE_CHOWN 1 + +/* Define if you have the 'chroot' function. */ +/* #define HAVE_CHROOT 1 */ // original: #define HAVE_CHROOT 1 + +/* Define to 1 if you have the `clock' function. */ +#define HAVE_CLOCK 1 + +/* Define to 1 if you have the `clock_getres' function. */ +/* #define HAVE_CLOCK_GETRES 1 */ // original: #define HAVE_CLOCK_GETRES 1 + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #define HAVE_CLOCK_GETTIME 1 */ // original: #define HAVE_CLOCK_GETTIME 1 + +/* Define if the C compiler supports computed gotos. */ +/* #undef HAVE_COMPUTED_GOTOS */ + +/* Define to 1 if you have the `confstr' function. */ +/* #define HAVE_CONFSTR 1 */ // original: #define HAVE_CONFSTR 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CONIO_H */ + +/* Define to 1 if you have the `copysign' function. */ +#define HAVE_COPYSIGN 1 + +/* Define to 1 if you have the `ctermid' function. */ +/* #define HAVE_CTERMID 1 */ // original: #define HAVE_CTERMID 1 + +/* Define if you have the 'ctermid_r' function. */ +/* #undef HAVE_CTERMID_R */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CURSES_H */ + +/* Define if you have the 'is_term_resized' function. */ +/* #undef HAVE_CURSES_IS_TERM_RESIZED */ + +/* Define if you have the 'resizeterm' function. */ +/* #undef HAVE_CURSES_RESIZETERM */ + +/* Define if you have the 'resize_term' function. */ +/* #undef HAVE_CURSES_RESIZE_TERM */ + +/* Define to 1 if you have the declaration of `isfinite', and to 0 if you + don't. */ +#define HAVE_DECL_ISFINITE 1 + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#define HAVE_DECL_ISINF 1 + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#define HAVE_DECL_ISNAN 1 + +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +#undef HAVE_DECL_TZNAME // original: #define HAVE_DECL_TZNAME 1 + +/* Define to 1 if you have the device macros. */ +/* #define HAVE_DEVICE_MACROS 1 */ // original: #define HAVE_DEVICE_MACROS 1 + +/* Define to 1 if you have the /dev/ptc device file. */ +/* #undef HAVE_DEV_PTC */ + +/* Define to 1 if you have the /dev/ptmx device file. */ +/* #undef HAVE_DEV_PTMX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if the dirent structure has a d_type field */ +#define HAVE_DIRENT_D_TYPE 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the 'dirfd' function or macro. */ +/* #undef HAVE_DIRFD */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `dlopen' function. */ +#undef HAVE_DLOPEN // original: #define HAVE_DLOPEN 1 + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the `dup3' function. */ +/* #define HAVE_DUP3 1 */ // original: #define HAVE_DUP3 1 + +/* Defined when any dynamic module loading is enabled. */ +#undef HAVE_DYNAMIC_LOADING // original: #define HAVE_DYNAMIC_LOADING 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define if you have the 'epoll' functions. */ +/* #undef HAVE_EPOLL */ + +/* Define if you have the 'epoll_create1' function. */ +/* #undef HAVE_EPOLL_CREATE1 */ + +/* Define to 1 if you have the `erf' function. */ +#define HAVE_ERF 1 + +/* Define to 1 if you have the `erfc' function. */ +#define HAVE_ERFC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `execv' function. */ +#undef HAVE_EXECV // original: #define HAVE_EXECV 1 + +/* Define to 1 if you have the `expm1' function. */ +#define HAVE_EXPM1 1 + +/* Define to 1 if you have the `faccessat' function. */ +/* #define HAVE_FACCESSAT 1 */ // original: #define HAVE_FACCESSAT 1 + +/* Define if you have the 'fchdir' function. */ +/* #define HAVE_FCHDIR 1 */ // #define HAVE_FCHDIR 1 + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the `fchmodat' function. */ +/* #define HAVE_FCHMODAT 1 */ // original: #define HAVE_FCHMODAT 1 + +/* Define to 1 if you have the `fchown' function. */ +/* #define HAVE_FCHOWN 1 */ // original: #define HAVE_FCHOWN 1 + +/* Define to 1 if you have the `fchownat' function. */ +#define HAVE_FCHOWNAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the 'fdatasync' function. */ +#undef HAVE_FDATASYNC // original: #define HAVE_FDATASYNC 1 + +/* Define to 1 if you have the `fdopendir' function. */ +/* #define HAVE_FDOPENDIR 1 */ // original: #define HAVE_FDOPENDIR 1 + +/* Define to 1 if you have the `fexecve' function. */ +#define HAVE_FEXECVE 1 + +/* Define to 1 if you have the `finite' function. */ +#define HAVE_FINITE 1 + +/* Define to 1 if you have the `flock' function. */ +#define HAVE_FLOCK 1 + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK // original: #define HAVE_FORK 1 + +/* Define to 1 if you have the `forkpty' function. */ +#undef HAVE_FORKPTY // original: #define HAVE_FORKPTY 1 + +/* Define to 1 if you have the `fpathconf' function. */ +/* #define HAVE_FPATHCONF 1 */ // original: #define HAVE_FPATHCONF 1 + +/* Define to 1 if you have the `fseek64' function. */ +#define HAVE_FSEEK64 1 + +/* Define to 1 if you have the `fseeko' function. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fstatat' function. */ +/* #define HAVE_FSTATAT 1 */ // original: #define HAVE_FSTATAT 1 + +/* Define to 1 if you have the `fstatvfs' function. */ +#define HAVE_FSTATVFS 1 + +/* Define if you have the 'fsync' function. */ +#define HAVE_FSYNC 1 + +/* Define to 1 if you have the `ftell64' function. */ +#define HAVE_FTELL64 1 + +/* Define to 1 if you have the `ftello' function. */ +#define HAVE_FTELLO 1 + +/* Define to 1 if you have the `ftime' function. */ +/* #define HAVE_FTIME 1 */ // original: #define HAVE_FTIME 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `futimens' function. */ +/* #define HAVE_FUTIMENS 1 */ // original: #define HAVE_FUTIMENS 1 + +/* Define to 1 if you have the `futimes' function. */ +/* #define HAVE_FUTIMES 1 */ // original: #define HAVE_FUTIMES 1 + +/* Define to 1 if you have the `futimesat' function. */ +/* #define HAVE_FUTIMESAT 1 */ // original: #define HAVE_FUTIMESAT 1 + +/* Define to 1 if you have the `gai_strerror' function. */ +#define HAVE_GAI_STRERROR 1 + +/* Define to 1 if you have the `gamma' function. */ +#define HAVE_GAMMA 1 + +/* Define if we can use gcc inline assembler to get and set mc68881 fpcr */ +/* #undef HAVE_GCC_ASM_FOR_MC68881 */ + +/* Define if we can use x64 gcc inline assembler */ +/* #undef HAVE_GCC_ASM_FOR_X64 */ + +/* Define if we can use gcc inline assembler to get and set x87 control word + */ +/* #undef HAVE_GCC_ASM_FOR_X87 */ + +/* Define if your compiler provides __uint128_t */ +#define HAVE_GCC_UINT128_T 1 + +/* Define if you have the getaddrinfo function. */ +#define HAVE_GETADDRINFO + +// TODO clarify what these are +#define SOCK_RAW 3 + +#define SOCK_SEQPACKET 5 + +#define IN_CLASSA_NSHIFT 24 + +/* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ +#undef HAVE_GETC_UNLOCKED // original: #define HAVE_GETC_UNLOCKED 1 + +/* Define to 1 if you have the `getentropy' function. */ +#undef HAVE_GETENTROPY // original: #define HAVE_GETENTROPY 1 + +/* Define to 1 if you have the `getgrouplist' function. */ +/* #define HAVE_GETGROUPLIST 1 */ // original: #define HAVE_GETGROUPLIST 1 + +/* Define to 1 if you have the `getgroups' function. */ +/* #define HAVE_GETGROUPS 1 */ // original: #define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define this if you have some version of gethostbyname_r() */ +#define HAVE_GETHOSTBYNAME_R 1 + +/* Define this if you have the 3-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_3_ARG */ + +/* Define this if you have the 5-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_5_ARG */ + +/* Define this if you have the 6-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_6_ARG */ + +/* Define to 1 if you have the `getitimer' function. */ +#undef HAVE_GETITIMER // original: #define HAVE_GETITIMER 1 + +/* Define to 1 if you have the `getloadavg' function. */ +/* #define HAVE_GETLOADAVG 1 */ // original: #define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getlogin' function. */ +/* #define HAVE_GETLOGIN 1 */ // original: #define HAVE_GETLOGIN 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#undef HAVE_GETNAMEINFO + +/* Define if you have the 'getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getpeername' function. */ +#define HAVE_GETPEERNAME 1 + +/* Define to 1 if you have the `getpgid' function. */ +/* #define HAVE_GETPGID 1 */ // original: #define HAVE_GETPGID 1 + +/* Define to 1 if you have the `getpgrp' function. */ +/* #define HAVE_GETPGRP 1 */ // original: #define HAVE_GETPGRP 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpriority' function. */ +/* #define HAVE_GETPRIORITY 1 */ // original: #define HAVE_GETPRIORITY 1 + +/* Define to 1 if you have the `getpwent' function. */ +#undef HAVE_GETPWENT // original: #define HAVE_GETPWENT 1 + +/* Define to 1 if the getrandom() function is available */ +/* #undef HAVE_GETRANDOM */ + +/* Define to 1 if the Linux getrandom() syscall is available */ +/* #undef HAVE_GETRANDOM_SYSCALL */ + +/* Define to 1 if you have the `getresgid' function. */ +/* #define HAVE_GETRESGID 1 */ // original: #define HAVE_GETRESGID 1 + +/* Define to 1 if you have the `getresuid' function. */ +/* #define HAVE_GETRESUID 1 */ // original: #define HAVE_GETRESUID 1 + +/* Define to 1 if you have the `getsid' function. */ +/* #define HAVE_GETSID 1 */ // original: #define HAVE_GETSID 1 + +/* Define to 1 if you have the `getspent' function. */ +#define HAVE_GETSPENT 1 + +/* Define to 1 if you have the `getspnam' function. */ +#define HAVE_GETSPNAM 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getwd' function. */ +#define HAVE_GETWD 1 + +/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and + bcopy. */ +/* #undef HAVE_GLIBC_MEMMOVE_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the 'hstrerror' function. */ +/* #undef HAVE_HSTRERROR */ + +/* Define this if you have le64toh() */ +#define HAVE_HTOLE64 1 + +/* Define to 1 if you have the `hypot' function. */ +#define HAVE_HYPOT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IEEEFP_H 1 + +/* Define to 1 if you have the `if_nameindex' function. */ +/* #define HAVE_IF_NAMEINDEX 1 */ // original: #define HAVE_IF_NAMEINDEX 1 + +/* Define if you have the 'inet_aton' function. */ +/* #define HAVE_INET_ATON 1 */ // original: #define HAVE_INET_ATON 1 + +/* Define if you have the 'inet_pton' function. */ +#define HAVE_INET_PTON 1 + +/* Define to 1 if you have the `initgroups' function. */ +/* #define HAVE_INITGROUPS 1 */ // original: #define HAVE_INITGROUPS 1 + +/* Define if your compiler provides int32_t. */ +#define HAVE_INT32_T 1 + +/* Define if your compiler provides int64_t. */ +#define HAVE_INT64_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define if gcc has the ipa-pure-const bug. */ +/* #undef HAVE_IPA_PURE_CONST_BUG */ + +/* Define to 1 if you have the `kill' function. */ +#undef HAVE_KILL // original: #define HAVE_KILL 1 + +/* Define to 1 if you have the `killpg' function. */ +#undef HAVE_KILLPG // original: #define HAVE_KILLPG 1 + +/* Define if you have the 'kqueue' functions. */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LANGINFO_H 1 + +/* Defined to enable large file support when an off_t is bigger than a long + and long long is available and at least as big as an off_t. You may need to + add some flags for configuration and compilation to enable this mode. (For + Solaris and Linux, the necessary defines are already defined.) */ +/* #undef HAVE_LARGEFILE_SUPPORT */ + +/* Define to 1 if you have the 'lchflags' function. */ +/* #define HAVE_LCHFLAGS 1 */ // original: #define HAVE_LCHFLAGS 1 + +/* Define to 1 if you have the `lchmod' function. */ +/* #define HAVE_LCHMOD 1 */ // original: #define HAVE_LCHMOD 1 + +/* Define to 1 if you have the `lchown' function. */ +/* #define HAVE_LCHOWN 1 */ // original: #define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `lgamma' function. */ +#define HAVE_LGAMMA 1 + +/* Define to 1 if you have the `dl' library (-ldl). */ +/* #undef HAVE_LIBDL */ + +/* Define to 1 if you have the `dld' library (-ldld). */ +/* #undef HAVE_LIBDLD */ + +/* Define to 1 if you have the `ieee' library (-lieee). */ +/* #undef HAVE_LIBIEEE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define if you have the readline library (-lreadline). */ +/* #undef HAVE_LIBREADLINE */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +/* #undef HAVE_LIBRESOLV */ + +/* Define to 1 if you have the `sendfile' library (-lsendfile). */ +/* #undef HAVE_LIBSENDFILE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the 'link' function. */ +#define HAVE_LINK 1 + +/* Define to 1 if you have the `linkat' function. */ +/* #define HAVE_LINKAT 1 */ // original: #define HAVE_LINKAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_CAN_BCM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_CAN_H */ + +/* Define if compiling using Linux 3.6 or later. */ +/* #undef HAVE_LINUX_CAN_RAW_FD_FRAMES */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_CAN_RAW_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_NETLINK_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_RANDOM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_TIPC_H */ + +/* Define to 1 if you have the `lockf' function. */ +/* #define HAVE_LOCKF 1 */ // original: #define HAVE_LOCKF 1 + +/* Define to 1 if you have the `log1p' function. */ +#define HAVE_LOG1P 1 + +/* Define to 1 if you have the `log2' function. */ +#define HAVE_LOG2 1 + +/* Define this if you have the type long double. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define this if you have the type long long. */ +#define HAVE_LONG_LONG 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 /* We don't really have lstat, but sed replaces it with stat */ + +/* Define to 1 if you have the `lutimes' function. */ +/* #define HAVE_LUTIMES 1 */ // original: #define HAVE_LUTIMES 1 + +/* Define this if you have the makedev macro. */ +/* #define HAVE_MAKEDEV 1 */ // original: #define HAVE_MAKEDEV 1 + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memrchr' function. */ +#define HAVE_MEMRCHR 1 + +/* Define to 1 if you have the `mkdirat' function. */ +/* #define HAVE_MKDIRAT 1 */ // #define HAVE_MKDIRAT 1 + +/* Define to 1 if you have the `mkfifo' function. */ +/* #define HAVE_MKFIFO 1 */ // original: #define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mkfifoat' function. */ +#define HAVE_MKFIFOAT 1 + +/* Define to 1 if you have the `mknod' function. */ +/* #define HAVE_MKNOD 1 */ // original: #define HAVE_MKNOD 1 + +/* Define to 1 if you have the `mknodat' function. */ +#define HAVE_MKNODAT 1 + +/* Define to 1 if you have the `mktime' function. */ +#define HAVE_MKTIME 1 + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP // original: #define HAVE_MMAP 1 + +/* Define to 1 if you have the `mremap' function. */ +#define HAVE_MREMAP 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NCURSES_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETPACKET_PACKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have the `nice' function. */ +/* #define HAVE_NICE 1 */ // original: #define HAVE_NICE 1 + +/* Define to 1 if you have the `openat' function. */ +/* #define HAVE_OPENAT 1 */ // original: #define HAVE_OPENAT 1 + +/* Define to 1 if you have the `openpty' function. */ +#undef HAVE_OPENPTY // original: #define HAVE_OPENPTY 1 + +/* Define if compiling using MacOS X 10.5 SDK or later. */ +/* #undef HAVE_OSX105_SDK */ + +/* Define to 1 if you have the `pathconf' function. */ +/* #define HAVE_PATHCONF 1 */ // original: #define HAVE_PATHCONF 1 + +/* Define to 1 if you have the `pause' function. */ +#undef HAVE_PAUSE // original: #define HAVE_PAUSE 1 + +/* Define to 1 if you have the `pipe2' function. */ +/* #define HAVE_PIPE2 1 */ // original: #define HAVE_PIPE2 1 + +/* Define to 1 if you have the `plock' function. */ +/* #define HAVE_PLOCK 1 */ // original: #define HAVE_PLOCK 1 + +/* Define to 1 if you have the `poll' function. */ +/* #define HAVE_POLL 1 */ // original: #define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_POLL_H */ // original: #define HAVE_POLL_H 1 + +/* Define to 1 if you have the `posix_fadvise' function. */ +/* #define HAVE_POSIX_FADVISE 1 */ // original: #define HAVE_POSIX_FADVISE 1 + +/* Define to 1 if you have the `posix_fallocate' function. */ +/* #define HAVE_POSIX_FALLOCATE 1 */ // original: #define HAVE_POSIX_FALLOCATE 1 + +/* Define to 1 if you have the `pread' function. */ +/* #define HAVE_PREAD 1 */ // original: #define HAVE_PREAD 1 + +/* Define if you have the 'prlimit' functions. */ +/* #undef HAVE_PRLIMIT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PROCESS_H */ + +/* Define if your compiler supports function prototype */ +#define HAVE_PROTOTYPES 1 + +/* Define to 1 if you have the `pthread_atfork' function. */ +/* #undef HAVE_PTHREAD_ATFORK */ + +/* Defined for Solaris 2.6 bug in pthread header. */ +/* #undef HAVE_PTHREAD_DESTRUCTOR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the `pthread_init' function. */ +#define HAVE_PTHREAD_INIT 1 + +/* Define to 1 if you have the `pthread_kill' function. */ +#define HAVE_PTHREAD_KILL 1 + +/* Define to 1 if you have the `pthread_sigmask' function. */ +/* #undef HAVE_PTHREAD_SIGMASK */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define to 1 if you have the `putenv' function. */ +#define HAVE_PUTENV 1 + +/* Define to 1 if you have the `pwrite' function. */ +/* #define HAVE_PWRITE 1 */ // original: #define HAVE_PWRITE 1 + +/* Define to 1 if you have the `readlink' function. */ +#undef HAVE_READLINK // original: #define HAVE_READLINK 1 + +/* Define to 1 if you have the `readlinkat' function. */ +#define HAVE_READLINKAT 1 + +/* Define to 1 if you have the `readv' function. */ +/* #define HAVE_READV 1 */ // original: #define HAVE_READV 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the `renameat' function. */ +/* #define HAVE_RENAMEAT 1 */ // original: #define HAVE_RENAMEAT 1 + +/* Define if readline supports append_history */ +/* #undef HAVE_RL_APPEND_HISTORY */ + +/* Define if you have readline 2.1 */ +/* #undef HAVE_RL_CALLBACK */ + +/* Define if you can turn off readline's signal handling. */ +/* #undef HAVE_RL_CATCH_SIGNAL */ + +/* Define if you have readline 2.2 */ +/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */ + +/* Define if you have readline 4.0 */ +/* #undef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK */ + +/* Define if you have readline 4.2 */ +/* #undef HAVE_RL_COMPLETION_MATCHES */ + +/* Define if you have rl_completion_suppress_append */ +/* #undef HAVE_RL_COMPLETION_SUPPRESS_APPEND */ + +/* Define if you have readline 4.0 */ +/* #undef HAVE_RL_PRE_INPUT_HOOK */ + +/* Define if you have readline 4.0 */ +/* #undef HAVE_RL_RESIZE_TERMINAL */ + +/* Define to 1 if you have the `round' function. */ +#define HAVE_ROUND 1 + +/* Define to 1 if you have the `sched_get_priority_max' function. */ +/* #define HAVE_SCHED_GET_PRIORITY_MAX 1 */ // original: #define HAVE_SCHED_GET_PRIORITY_MAX 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SCHED_H 1 */ // original: #define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `sched_rr_get_interval' function. */ +/* #define HAVE_SCHED_RR_GET_INTERVAL 1 */ // original: #define HAVE_SCHED_RR_GET_INTERVAL 1 + +/* Define to 1 if you have the `sched_setaffinity' function. */ +#define HAVE_SCHED_SETAFFINITY 1 + +/* Define to 1 if you have the `sched_setparam' function. */ +/* #define HAVE_SCHED_SETPARAM 1 */ //original: #define HAVE_SCHED_SETPARAM 1 + +/* Define to 1 if you have the `sched_setscheduler' function. */ +/* #define HAVE_SCHED_SETSCHEDULER 1 */ // original: #define HAVE_SCHED_SETSCHEDULER 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `sem_getvalue' function. */ +#define HAVE_SEM_GETVALUE 1 + +/* Define to 1 if you have the `sem_open' function. */ +#define HAVE_SEM_OPEN 1 + +/* Define to 1 if you have the `sem_timedwait' function. */ +#define HAVE_SEM_TIMEDWAIT 1 + +/* Define to 1 if you have the `sem_unlink' function. */ +#define HAVE_SEM_UNLINK 1 + +/* Define to 1 if you have the `sendfile' function. */ +/* #define HAVE_SENDFILE 1 */ // original: #define HAVE_SENDFILE 1 + +/* Define to 1 if you have the `setegid' function. */ +/* #define HAVE_SETEGID 1 */ // original: #define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +/* #define HAVE_SETEUID 1 */ // original: #define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setgid' function. */ +/* #define HAVE_SETGID 1 */ // original: #define HAVE_SETGID 1 + +/* Define if you have the 'setgroups' function. */ +/* #define HAVE_SETGROUPS 1 */ // original: #define HAVE_SETGROUPS 1 + +/* Define to 1 if you have the `sethostname' function. */ +/* #define HAVE_SETHOSTNAME 1 */ // original: #define HAVE_SETHOSTNAME 1 + +/* Define to 1 if you have the `setitimer' function. */ +/* #define HAVE_SETITIMER 1 */ // original: #define HAVE_SETITIMER 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setpgid' function. */ +/* #define HAVE_SETPGID 1 */ // original: #define HAVE_SETPGID 1 + +/* Define to 1 if you have the `setpgrp' function. */ +/* #define HAVE_SETPGRP 1 */ // original: #define HAVE_SETPGRP 1 + +/* Define to 1 if you have the `setpriority' function. */ +/* #define HAVE_SETPRIORITY 1 */ // original: #define HAVE_SETPRIORITY 1 + +/* Define to 1 if you have the `setregid' function. */ +/* #define HAVE_SETREGID 1 */ // original: #define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setresgid' function. */ +/* #define HAVE_SETRESGID 1 */ // original: #define HAVE_SETRESGID 1 + +/* Define to 1 if you have the `setresuid' function. */ +/* #define HAVE_SETRESUID 1 */ // original: #define HAVE_SETRESUID 1 + +/* Define to 1 if you have the `setreuid' function. */ +/* #define HAVE_SETREUID 1 */ // original: #define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setsid' function. */ +/* #define HAVE_SETSID 1 */ // original: #define HAVE_SETSID 1 + +/* Define to 1 if you have the `setuid' function. */ +/* #define HAVE_SETUID 1 */ // original: #define HAVE_SETUID 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION // original: #define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigaltstack' function. */ +/* #define HAVE_SIGALTSTACK 1 */ // original: #define HAVE_SIGALTSTACK 1 + +/* Define to 1 if you have the `siginterrupt' function. */ +#undef HAVE_SIGINTERRUPT // original: #define HAVE_SIGINTERRUPT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `sigpending' function. */ +#define HAVE_SIGPENDING 1 + +/* Define to 1 if you have the `sigrelse' function. */ +#define HAVE_SIGRELSE 1 + +/* Define to 1 if you have the `sigtimedwait' function. */ +#define HAVE_SIGTIMEDWAIT 1 + +/* Define to 1 if you have the `sigwait' function. */ +#define HAVE_SIGWAIT 1 + +/* Define to 1 if you have the `sigwaitinfo' function. */ +#define HAVE_SIGWAITINFO 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define if sockaddr has sa_len member */ +/* #define HAVE_SOCKADDR_SA_LEN 1 */ // original: #define HAVE_SOCKADDR_SA_LEN 1 + +/* struct sockaddr_storage (sys/socket.h) */ +#define HAVE_SOCKADDR_STORAGE 1 + +/* Define if you have the 'socketpair' function. */ +/* #define HAVE_SOCKETPAIR 1 */ // original: #define HAVE_SOCKETPAIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SPAWN_H 1 + +/* Define if your compiler provides ssize_t */ +#define HAVE_SSIZE_T 1 + +/* Define to 1 if you have the `statvfs' function. */ +#undef HAVE_STATVFS // original: #define HAVE_STATVFS 1 + +/* Define if you have struct stat.st_mtim.tv_nsec */ +/* #undef HAVE_STAT_TV_NSEC */ + +/* Define if you have struct stat.st_mtimensec */ +/* #undef HAVE_STAT_TV_NSEC2 */ + +/* Define if your compiler supports variable length function prototypes (e.g. + void fprintf(FILE *, char *, ...);) *and* */ +#define HAVE_STDARG_PROTOTYPES 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Has stdatomic.h, atomic_int and _Atomic void* types work */ +#define HAVE_STD_ATOMIC 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if `st_flags' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ + +/* Define to 1 if `st_gen' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_GEN */ + +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM_TM_ZONE */ + +/* Define if you have the 'symlink' function. */ +#undef HAVE_SYMLINK // original: #define HAVE_SYMLINK 1 + +/* Define to 1 if you have the `symlinkat' function. */ +#define HAVE_SYMLINKAT 1 + +/* Define to 1 if you have the `sync' function. */ +/* #define HAVE_SYNC 1 */ // original: #define HAVE_SYNC 1 + +/* Define to 1 if you have the `sysconf' function. */ +/* #define HAVE_SYSCONF 1 */ // original: #define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYSEXITS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_AUDIOIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BSDTTY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DEVPOLL_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EPOLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_KERN_CONTROL_H */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_LOADAVG_H // original: /* #undef HAVE_SYS_LOADAVG_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_LOCK_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MKDEV_H // original: /* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MODEM_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_POLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_RANDOM_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_RESOURCE_H 1 */ // original: #define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SENDFILE_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_SOCKET_H 1 */ // original: #define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STATVFS_H // original: #define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCALL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYS_DOMAIN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TERMIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UTSNAME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the `tcgetpgrp' function. */ +/* #define HAVE_TCGETPGRP 1 */ // original: #define HAVE_TCGETPGRP 1 + +/* Define to 1 if you have the `tcsetpgrp' function. */ +/* #define HAVE_TCSETPGRP 1 */ // original: #define HAVE_TCSETPGRP 1 + +/* Define to 1 if you have the `tempnam' function. */ +#define HAVE_TEMPNAM 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TERMIOS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TERM_H */ + +/* Define to 1 if you have the `tgamma' function. */ +#define HAVE_TGAMMA 1 + +/* Define to 1 if you have the `timegm' function. */ +#define HAVE_TIMEGM 1 + +/* Define to 1 if you have the `times' function. */ +#define HAVE_TIMES 1 + +/* Define to 1 if you have the `tmpfile' function. */ +#define HAVE_TMPFILE 1 + +/* Define to 1 if you have the `tmpnam' function. */ +#define HAVE_TMPNAM 1 + +/* Define to 1 if you have the `tmpnam_r' function. */ +#define HAVE_TMPNAM_R 1 + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +/* #undef HAVE_TM_ZONE */ + +/* Define to 1 if you have the `truncate' function. */ +#define HAVE_TRUNCATE 1 + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +#undef HAVE_TZNAME // original: #define HAVE_TZNAME 1 + +/* Define this if you have tcl and TCL_UTF_MAX==6 */ +/* #undef HAVE_UCS4_TCL */ + +/* Define if your compiler provides uint32_t. */ +#define HAVE_UINT32_T 1 + +/* Define if your compiler provides uint64_t. */ +#define HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uintptr_t'. */ +#define HAVE_UINTPTR_T 1 + +/* Define to 1 if you have the `uname' function. */ +/* #define HAVE_UNAME 1 */ // original: #define HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unlinkat' function. */ +/* #define HAVE_UNLINKAT 1 */ // original: #define HAVE_UNLINKAT 1 + +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + +/* Define if you have a useable wchar_t type defined in wchar.h; useable means + wchar_t must be an unsigned type with at least 16 bits. (see + Include/unicodeobject.h). */ +/* #undef HAVE_USABLE_WCHAR_T */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTIL_H */ + +/* Define to 1 if you have the `utimensat' function. */ +/* #define HAVE_UTIMENSAT 1 */ // original: #define HAVE_UTIMENSAT 1 + +/* Define to 1 if you have the `utimes' function. */ +/* #define HAVE_UTIMES 1 */ // original: #define HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_UTIME_H 1 */ // original: #define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `wait3' function. */ +/* #define HAVE_WAIT3 1 */ // original: #define HAVE_WAIT3 1 + +/* Define to 1 if you have the `wait4' function. */ +/* #define HAVE_WAIT4 1 */ // original: #define HAVE_WAIT4 1 + +/* Define to 1 if you have the `waitid' function. */ +/* #define HAVE_WAITID 1 */ // original: #define HAVE_WAITID 1 + +/* Define to 1 if you have the `waitpid' function. */ +/* #define HAVE_WAITPID 1 */ // original: #define HAVE_WAITPID 1 + +/* Define if the compiler provides a wchar.h header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the `wcscoll' function. */ +#define HAVE_WCSCOLL 1 + +/* Define to 1 if you have the `wcsftime' function. */ +#define HAVE_WCSFTIME 1 + +/* Define to 1 if you have the `wcsxfrm' function. */ +#define HAVE_WCSXFRM 1 + +/* Define to 1 if you have the `wmemcmp' function. */ +#define HAVE_WMEMCMP 1 + +/* Define if tzset() actually switches the local timezone in a meaningful way. + */ +/* #undef HAVE_WORKING_TZSET */ + +/* Define to 1 if you have the `writev' function. */ +/* #define HAVE_WRITEV 1 */ // orignal: #define HAVE_WRITEV 1 + +/* Define if the zlib library has inflateCopy */ +/* #undef HAVE_ZLIB_COPY */ + +/* Define to 1 if you have the `_getpty' function. */ +/* #define HAVE__GETPTY 1 */ // original: #define HAVE__GETPTY 1 + +/* Define if log1p(-0.) is 0. rather than -0. */ +/* #undef LOG1P_DROPS_ZERO_SIGN */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +#undef MAJOR_IN_MKDEV // original: /* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define if mvwdelch in curses.h is an expression. */ +/* #undef MVWDELCH_IS_EXPRESSION */ + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +/* #undef PACKAGE_NAME */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the home page for this package. */ +/* #undef PACKAGE_URL */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* Define if POSIX semaphores aren't enabled on your system */ +/* #undef POSIX_SEMAPHORES_NOT_ENABLED */ + +/* Defined if PTHREAD_SCOPE_SYSTEM supported. */ +/* #undef PTHREAD_SYSTEM_SCHED_SUPPORTED */ + +/* Define as the preferred size in bits of long digits */ +/* #undef PYLONG_BITS_IN_DIGIT */ + +/* Define to printf format modifier for long long type */ +#define PY_FORMAT_LONG_LONG "ll" // original: #undef PY_FORMAT_LONG_LONG + +/* Define to printf format modifier for Py_ssize_t */ +#define PY_FORMAT_SIZE_T "z" + +/* Define if you want to build an interpreter with many run-time checks. */ +/* #undef Py_DEBUG */ + +/* Defined if Python is built as a shared library. */ +/* #undef Py_ENABLE_SHARED */ + +/* Define hash algorithm for str, bytes and memoryview. SipHash24: 1, FNV: 2, + externally defined: 0 */ +/* #undef Py_HASH_ALGORITHM */ + +/* assume C89 semantics that RETSIGTYPE is always void */ +#define RETSIGTYPE void + +/* Define if setpgrp() must be called as setpgrp(0, 0). */ +/* #undef SETPGRP_HAVE_ARG */ + +/* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ +/* #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS */ + +/* The size of `double', as computed by sizeof. */ +#define SIZEOF_DOUBLE 8 + +/* The size of `float', as computed by sizeof. */ +#define SIZEOF_FLOAT 4 + +/* The size of `fpos_t', as computed by sizeof. */ +#define SIZEOF_FPOS_T 8 + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `long double', as computed by sizeof. */ +#define SIZEOF_LONG_DOUBLE 16 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `off_t', as computed by sizeof. */ +#define SIZEOF_OFF_T 8 + +/* The size of `pid_t', as computed by sizeof. */ +#define SIZEOF_PID_T 4 + +/* The size of `pthread_t', as computed by sizeof. */ +#define SIZEOF_PTHREAD_T 4 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 8 + +/* The size of `uintptr_t', as computed by sizeof. */ +#define SIZEOF_UINTPTR_T 8 + +/* The size of `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 8 + +/* The size of `wchar_t', as computed by sizeof. */ +#define SIZEOF_WCHAR_T 4 + +/* The size of `_Bool', as computed by sizeof. */ +#define SIZEOF__BOOL 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and + (which you can't on SCO ODT 3.0). */ +#define SYS_SELECT_WITH_SYS_TIME 1 + +/* Define if tanh(-0.) is -0., or if platform doesn't have signed zeros */ +/* #undef TANH_PRESERVES_ZERO_SIGN */ + +/* Library needed by timemodule.c: librt may be needed for clock_gettime() */ +/* #undef TIMEMODULE_LIB */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define if you want to use computed gotos in ceval.c. */ +/* #undef USE_COMPUTED_GOTOS */ + +/* Define to use the C99 inline keyword. */ +#define USE_INLINE 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Define if a va_list is an array of some kind */ +/* #undef VA_LIST_IS_ARRAY */ + +/* Define if you want SIGFPE handled (see Include/pyfpe.h). */ +/* #undef WANT_SIGFPE_HANDLER */ + +/* Define if WINDOW in curses.h offers a field _flags. */ +/* #undef WINDOW_HAS_FLAGS */ + +/* Define if you want documentation strings in extension modules */ +/* #undef WITH_DOC_STRINGS */ + +/* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic + linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). + Dyld is necessary to support frameworks. */ +/* #undef WITH_DYLD */ + +/* Define to 1 if libintl is needed for locale functions. */ +/* #undef WITH_LIBINTL */ + +/* Define if you want to produce an OpenStep/Rhapsody framework (shared + library plus accessory files). */ +/* #undef WITH_NEXT_FRAMEWORK */ + +/* Define if you want to compile in Python-specific mallocs */ +#define WITH_PYMALLOC 1 + +/* Define if you want to compile in rudimentary thread support */ +#define WITH_THREAD + +/* Define to profile with the Pentium timestamp counter */ +/* #undef WITH_TSC */ + +/* Define if you want pymalloc to be disabled when running under valgrind */ +/* #undef WITH_VALGRIND */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define if arithmetic is subject to x87-style double rounding issue */ +/* #undef X87_DOUBLE_ROUNDING */ + +/* Define on OpenBSD to activate all library features */ +/* #undef _BSD_SOURCE */ + +/* Define on Irix to enable u_int */ +#define _BSD_TYPES 1 + +/* Define on Darwin to activate all library features */ +#define _DARWIN_C_SOURCE 1 + +/* This must be set to 64 on some systems to enable large file support. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define on Linux to activate all library features */ +#define _GNU_SOURCE 1 + +/* Define to include mbstate_t for mbrtowc */ +/* #undef _INCLUDE__STDC_A1_SOURCE */ + +/* This must be defined on some systems to enable large file support. */ +/* #undef _LARGEFILE_SOURCE */ + +/* This must be defined on AIX systems to enable large file support. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define on NetBSD to activate all library features */ +#define _NETBSD_SOURCE 1 + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to activate features from IEEE Stds 1003.1-2008 */ +#define _POSIX_C_SOURCE 200809L + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define if you have POSIX threads, and your system does not define that. */ +/* #undef _POSIX_THREADS */ + +/* Define to force use of thread-safe errno, h_errno, and other functions */ +/* #undef _REENTRANT */ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define to the level of X/Open that your system supports */ +#define _XOPEN_SOURCE 700 + +/* Define to activate Unix95-and-earlier features */ +#define _XOPEN_SOURCE_EXTENDED 1 + +/* Define on FreeBSD to activate all library features */ +#define __BSD_VISIBLE 1 + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +/* # undef __CHAR_UNSIGNED__ */ +#endif + +/* Define to 'long' if doesn't define. */ +/* #undef clock_t */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int64_t */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to empty if the keyword does not work. */ +/* #undef signed */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #define socklen_t int */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to empty if the keyword does not work. */ +/* #undef volatile */ + + +/* Define the macros needed if on a UnixWare 7.x system. */ +#if defined(__USLC__) && defined(__SCO_VERSION__) +#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ +#endif + +#endif /*Py_PYCONFIG_H*/ + diff --git a/libs/nxpy/include/pyctype.h b/libs/nxpy/include/pyctype.h index 6bce63ee..ee22795a 100644 --- a/libs/nxpy/include/pyctype.h +++ b/libs/nxpy/include/pyctype.h @@ -1,33 +1,33 @@ -#ifndef Py_LIMITED_API -#ifndef PYCTYPE_H -#define PYCTYPE_H - -#define PY_CTF_LOWER 0x01 -#define PY_CTF_UPPER 0x02 -#define PY_CTF_ALPHA (PY_CTF_LOWER|PY_CTF_UPPER) -#define PY_CTF_DIGIT 0x04 -#define PY_CTF_ALNUM (PY_CTF_ALPHA|PY_CTF_DIGIT) -#define PY_CTF_SPACE 0x08 -#define PY_CTF_XDIGIT 0x10 - -PyAPI_DATA(const unsigned int) _Py_ctype_table[256]; - -/* Unlike their C counterparts, the following macros are not meant to - * handle an int with any of the values [EOF, 0-UCHAR_MAX]. The argument - * must be a signed/unsigned char. */ -#define Py_ISLOWER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_LOWER) -#define Py_ISUPPER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_UPPER) -#define Py_ISALPHA(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALPHA) -#define Py_ISDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_DIGIT) -#define Py_ISXDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_XDIGIT) -#define Py_ISALNUM(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALNUM) -#define Py_ISSPACE(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_SPACE) - -PyAPI_DATA(const unsigned char) _Py_ctype_tolower[256]; -PyAPI_DATA(const unsigned char) _Py_ctype_toupper[256]; - -#define Py_TOLOWER(c) (_Py_ctype_tolower[Py_CHARMASK(c)]) -#define Py_TOUPPER(c) (_Py_ctype_toupper[Py_CHARMASK(c)]) - -#endif /* !PYCTYPE_H */ -#endif /* !Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef PYCTYPE_H +#define PYCTYPE_H + +#define PY_CTF_LOWER 0x01 +#define PY_CTF_UPPER 0x02 +#define PY_CTF_ALPHA (PY_CTF_LOWER|PY_CTF_UPPER) +#define PY_CTF_DIGIT 0x04 +#define PY_CTF_ALNUM (PY_CTF_ALPHA|PY_CTF_DIGIT) +#define PY_CTF_SPACE 0x08 +#define PY_CTF_XDIGIT 0x10 + +PyAPI_DATA(const unsigned int) _Py_ctype_table[256]; + +/* Unlike their C counterparts, the following macros are not meant to + * handle an int with any of the values [EOF, 0-UCHAR_MAX]. The argument + * must be a signed/unsigned char. */ +#define Py_ISLOWER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_LOWER) +#define Py_ISUPPER(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_UPPER) +#define Py_ISALPHA(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALPHA) +#define Py_ISDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_DIGIT) +#define Py_ISXDIGIT(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_XDIGIT) +#define Py_ISALNUM(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_ALNUM) +#define Py_ISSPACE(c) (_Py_ctype_table[Py_CHARMASK(c)] & PY_CTF_SPACE) + +PyAPI_DATA(const unsigned char) _Py_ctype_tolower[256]; +PyAPI_DATA(const unsigned char) _Py_ctype_toupper[256]; + +#define Py_TOLOWER(c) (_Py_ctype_tolower[Py_CHARMASK(c)]) +#define Py_TOUPPER(c) (_Py_ctype_toupper[Py_CHARMASK(c)]) + +#endif /* !PYCTYPE_H */ +#endif /* !Py_LIMITED_API */ diff --git a/libs/nxpy/include/pydebug.h b/libs/nxpy/include/pydebug.h index 19bec2bd..2f458b6b 100644 --- a/libs/nxpy/include/pydebug.h +++ b/libs/nxpy/include/pydebug.h @@ -1,36 +1,36 @@ -#ifndef Py_LIMITED_API -#ifndef Py_PYDEBUG_H -#define Py_PYDEBUG_H -#ifdef __cplusplus -extern "C" { -#endif - -/* These global variable are defined in pylifecycle.c */ -/* XXX (ncoghlan): move these declarations to pylifecycle.h? */ -PyAPI_DATA(int) Py_DebugFlag; -PyAPI_DATA(int) Py_VerboseFlag; -PyAPI_DATA(int) Py_QuietFlag; -PyAPI_DATA(int) Py_InteractiveFlag; -PyAPI_DATA(int) Py_InspectFlag; -PyAPI_DATA(int) Py_OptimizeFlag; -PyAPI_DATA(int) Py_NoSiteFlag; -PyAPI_DATA(int) Py_BytesWarningFlag; -PyAPI_DATA(int) Py_UseClassExceptionsFlag; -PyAPI_DATA(int) Py_FrozenFlag; -PyAPI_DATA(int) Py_IgnoreEnvironmentFlag; -PyAPI_DATA(int) Py_DontWriteBytecodeFlag; -PyAPI_DATA(int) Py_NoUserSiteDirectory; -PyAPI_DATA(int) Py_UnbufferedStdioFlag; -PyAPI_DATA(int) Py_HashRandomizationFlag; -PyAPI_DATA(int) Py_IsolatedFlag; - -/* this is a wrapper around getenv() that pays attention to - Py_IgnoreEnvironmentFlag. It should be used for getting variables like - PYTHONPATH and PYTHONHOME from the environment */ -#define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv(s)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYDEBUG_H */ -#endif /* Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_PYDEBUG_H +#define Py_PYDEBUG_H +#ifdef __cplusplus +extern "C" { +#endif + +/* These global variable are defined in pylifecycle.c */ +/* XXX (ncoghlan): move these declarations to pylifecycle.h? */ +PyAPI_DATA(int) Py_DebugFlag; +PyAPI_DATA(int) Py_VerboseFlag; +PyAPI_DATA(int) Py_QuietFlag; +PyAPI_DATA(int) Py_InteractiveFlag; +PyAPI_DATA(int) Py_InspectFlag; +PyAPI_DATA(int) Py_OptimizeFlag; +PyAPI_DATA(int) Py_NoSiteFlag; +PyAPI_DATA(int) Py_BytesWarningFlag; +PyAPI_DATA(int) Py_UseClassExceptionsFlag; +PyAPI_DATA(int) Py_FrozenFlag; +PyAPI_DATA(int) Py_IgnoreEnvironmentFlag; +PyAPI_DATA(int) Py_DontWriteBytecodeFlag; +PyAPI_DATA(int) Py_NoUserSiteDirectory; +PyAPI_DATA(int) Py_UnbufferedStdioFlag; +PyAPI_DATA(int) Py_HashRandomizationFlag; +PyAPI_DATA(int) Py_IsolatedFlag; + +/* this is a wrapper around getenv() that pays attention to + Py_IgnoreEnvironmentFlag. It should be used for getting variables like + PYTHONPATH and PYTHONHOME from the environment */ +#define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv(s)) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYDEBUG_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/pyerrors.h b/libs/nxpy/include/pyerrors.h index 35aedb73..cead3e93 100644 --- a/libs/nxpy/include/pyerrors.h +++ b/libs/nxpy/include/pyerrors.h @@ -1,475 +1,475 @@ -#ifndef Py_ERRORS_H -#define Py_ERRORS_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Error objects */ - -#ifndef Py_LIMITED_API -/* PyException_HEAD defines the initial segment of every exception class. */ -#define PyException_HEAD PyObject_HEAD PyObject *dict;\ - PyObject *args; PyObject *traceback;\ - PyObject *context; PyObject *cause;\ - char suppress_context; - -typedef struct { - PyException_HEAD -} PyBaseExceptionObject; - -typedef struct { - PyException_HEAD - PyObject *msg; - PyObject *filename; - PyObject *lineno; - PyObject *offset; - PyObject *text; - PyObject *print_file_and_line; -} PySyntaxErrorObject; - -typedef struct { - PyException_HEAD - PyObject *msg; - PyObject *name; - PyObject *path; -} PyImportErrorObject; - -typedef struct { - PyException_HEAD - PyObject *encoding; - PyObject *object; - Py_ssize_t start; - Py_ssize_t end; - PyObject *reason; -} PyUnicodeErrorObject; - -typedef struct { - PyException_HEAD - PyObject *code; -} PySystemExitObject; - -typedef struct { - PyException_HEAD - PyObject *myerrno; - PyObject *strerror; - PyObject *filename; - PyObject *filename2; -#ifdef MS_WINDOWS - PyObject *winerror; -#endif - Py_ssize_t written; /* only for BlockingIOError, -1 otherwise */ -} PyOSErrorObject; - -typedef struct { - PyException_HEAD - PyObject *value; -} PyStopIterationObject; - -/* Compatibility typedefs */ -typedef PyOSErrorObject PyEnvironmentErrorObject; -#ifdef MS_WINDOWS -typedef PyOSErrorObject PyWindowsErrorObject; -#endif -#endif /* !Py_LIMITED_API */ - -/* Error handling definitions */ - -PyAPI_FUNC(void) PyErr_SetNone(PyObject *); -PyAPI_FUNC(void) PyErr_SetObject(PyObject *, PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); -#endif -PyAPI_FUNC(void) PyErr_SetString( - PyObject *exception, - const char *string /* decoded from utf-8 */ - ); -PyAPI_FUNC(PyObject *) PyErr_Occurred(void); -PyAPI_FUNC(void) PyErr_Clear(void); -PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); -PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); -PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); - -#if defined(__clang__) || \ - (defined(__GNUC_MAJOR__) && \ - ((__GNUC_MAJOR__ >= 3) || \ - (__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5))) -#define _Py_NO_RETURN __attribute__((__noreturn__)) -#else -#define _Py_NO_RETURN -#endif - -/* Defined in Python/pylifecycle.c */ -PyAPI_FUNC(void) Py_FatalError(const char *message) _Py_NO_RETURN; - -#if defined(Py_DEBUG) || defined(Py_LIMITED_API) -#define _PyErr_OCCURRED() PyErr_Occurred() -#else -#define _PyErr_OCCURRED() (PyThreadState_GET()->curexc_type) -#endif - -/* Error testing and normalization */ -PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); -PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); -PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); - -/* Traceback manipulation (PEP 3134) */ -PyAPI_FUNC(int) PyException_SetTraceback(PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *); - -/* Cause manipulation (PEP 3134) */ -PyAPI_FUNC(PyObject *) PyException_GetCause(PyObject *); -PyAPI_FUNC(void) PyException_SetCause(PyObject *, PyObject *); - -/* Context manipulation (PEP 3134) */ -PyAPI_FUNC(PyObject *) PyException_GetContext(PyObject *); -PyAPI_FUNC(void) PyException_SetContext(PyObject *, PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); -#endif - -/* */ - -#define PyExceptionClass_Check(x) \ - (PyType_Check((x)) && \ - PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)) - -#define PyExceptionInstance_Check(x) \ - PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS) - -#define PyExceptionClass_Name(x) \ - ((char *)(((PyTypeObject*)(x))->tp_name)) - -#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type)) - - -/* Predefined exceptions */ - -PyAPI_DATA(PyObject *) PyExc_BaseException; -PyAPI_DATA(PyObject *) PyExc_Exception; -PyAPI_DATA(PyObject *) PyExc_StopAsyncIteration; -PyAPI_DATA(PyObject *) PyExc_StopIteration; -PyAPI_DATA(PyObject *) PyExc_GeneratorExit; -PyAPI_DATA(PyObject *) PyExc_ArithmeticError; -PyAPI_DATA(PyObject *) PyExc_LookupError; - -PyAPI_DATA(PyObject *) PyExc_AssertionError; -PyAPI_DATA(PyObject *) PyExc_AttributeError; -PyAPI_DATA(PyObject *) PyExc_BufferError; -PyAPI_DATA(PyObject *) PyExc_EOFError; -PyAPI_DATA(PyObject *) PyExc_FloatingPointError; -PyAPI_DATA(PyObject *) PyExc_OSError; -PyAPI_DATA(PyObject *) PyExc_ImportError; -PyAPI_DATA(PyObject *) PyExc_IndexError; -PyAPI_DATA(PyObject *) PyExc_KeyError; -PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; -PyAPI_DATA(PyObject *) PyExc_MemoryError; -PyAPI_DATA(PyObject *) PyExc_NameError; -PyAPI_DATA(PyObject *) PyExc_OverflowError; -PyAPI_DATA(PyObject *) PyExc_RuntimeError; -PyAPI_DATA(PyObject *) PyExc_RecursionError; -PyAPI_DATA(PyObject *) PyExc_NotImplementedError; -PyAPI_DATA(PyObject *) PyExc_SyntaxError; -PyAPI_DATA(PyObject *) PyExc_IndentationError; -PyAPI_DATA(PyObject *) PyExc_TabError; -PyAPI_DATA(PyObject *) PyExc_ReferenceError; -PyAPI_DATA(PyObject *) PyExc_SystemError; -PyAPI_DATA(PyObject *) PyExc_SystemExit; -PyAPI_DATA(PyObject *) PyExc_TypeError; -PyAPI_DATA(PyObject *) PyExc_UnboundLocalError; -PyAPI_DATA(PyObject *) PyExc_UnicodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeEncodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError; -PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError; -PyAPI_DATA(PyObject *) PyExc_ValueError; -PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError; - -PyAPI_DATA(PyObject *) PyExc_BlockingIOError; -PyAPI_DATA(PyObject *) PyExc_BrokenPipeError; -PyAPI_DATA(PyObject *) PyExc_ChildProcessError; -PyAPI_DATA(PyObject *) PyExc_ConnectionError; -PyAPI_DATA(PyObject *) PyExc_ConnectionAbortedError; -PyAPI_DATA(PyObject *) PyExc_ConnectionRefusedError; -PyAPI_DATA(PyObject *) PyExc_ConnectionResetError; -PyAPI_DATA(PyObject *) PyExc_FileExistsError; -PyAPI_DATA(PyObject *) PyExc_FileNotFoundError; -PyAPI_DATA(PyObject *) PyExc_InterruptedError; -PyAPI_DATA(PyObject *) PyExc_IsADirectoryError; -PyAPI_DATA(PyObject *) PyExc_NotADirectoryError; -PyAPI_DATA(PyObject *) PyExc_PermissionError; -PyAPI_DATA(PyObject *) PyExc_ProcessLookupError; -PyAPI_DATA(PyObject *) PyExc_TimeoutError; - - -/* Compatibility aliases */ -PyAPI_DATA(PyObject *) PyExc_EnvironmentError; -PyAPI_DATA(PyObject *) PyExc_IOError; -#ifdef MS_WINDOWS -PyAPI_DATA(PyObject *) PyExc_WindowsError; -#endif - -PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst; - -/* Predefined warning categories */ -PyAPI_DATA(PyObject *) PyExc_Warning; -PyAPI_DATA(PyObject *) PyExc_UserWarning; -PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; -PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; -PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; -PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; -PyAPI_DATA(PyObject *) PyExc_FutureWarning; -PyAPI_DATA(PyObject *) PyExc_ImportWarning; -PyAPI_DATA(PyObject *) PyExc_UnicodeWarning; -PyAPI_DATA(PyObject *) PyExc_BytesWarning; -PyAPI_DATA(PyObject *) PyExc_ResourceWarning; - - -/* Convenience functions */ - -PyAPI_FUNC(int) PyErr_BadArgument(void); -PyAPI_FUNC(PyObject *) PyErr_NoMemory(void); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrno(PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObject( - PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObjects( - PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilename( - PyObject *exc, - const char *filename /* decoded from the filesystem encoding */ - ); -#if defined(MS_WINDOWS) && !defined(Py_LIMITED_API) -PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename( - PyObject *, const Py_UNICODE *); -#endif /* MS_WINDOWS */ - -PyAPI_FUNC(PyObject *) PyErr_Format( - PyObject *exception, - const char *format, /* ASCII-encoded string */ - ... - ); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -PyAPI_FUNC(PyObject *) PyErr_FormatV( - PyObject *exception, - const char *format, - va_list vargs); -#endif - -#ifdef MS_WINDOWS -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( - int ierr, - const char *filename /* decoded from the filesystem encoding */ - ); -#ifndef Py_LIMITED_API -/* XXX redeclare to use WSTRING */ -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename( - int, const Py_UNICODE *); -#endif -PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int); -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject( - PyObject *,int, PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObjects( - PyObject *,int, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename( - PyObject *exc, - int ierr, - const char *filename /* decoded from the filesystem encoding */ - ); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename( - PyObject *,int, const Py_UNICODE *); -#endif -PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); -#endif /* MS_WINDOWS */ - -PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, - PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, - PyObject *); - -/* Export the old function so that the existing API remains available: */ -PyAPI_FUNC(void) PyErr_BadInternalCall(void); -PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno); -/* Mask the old API with a call to the new API for code compiled under - Python 2.0: */ -#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) - -/* Function to create a new exception */ -PyAPI_FUNC(PyObject *) PyErr_NewException( - const char *name, PyObject *base, PyObject *dict); -PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc( - const char *name, const char *doc, PyObject *base, PyObject *dict); -PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *); - -/* In exceptions.c */ -#ifndef Py_LIMITED_API -/* Helper that attempts to replace the current exception with one of the - * same type but with a prefix added to the exception text. The resulting - * exception description looks like: - * - * prefix (exc_type: original_exc_str) - * - * Only some exceptions can be safely replaced. If the function determines - * it isn't safe to perform the replacement, it will leave the original - * unmodified exception in place. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( - const char *prefix_format, /* ASCII-encoded string */ - ... - ); -#endif - - -/* In sigcheck.c or signalmodule.c */ -PyAPI_FUNC(int) PyErr_CheckSignals(void); -PyAPI_FUNC(void) PyErr_SetInterrupt(void); - -/* In signalmodule.c */ -#ifndef Py_LIMITED_API -int PySignal_SetWakeupFd(int fd); -#endif - -/* Support for adding program text to SyntaxErrors */ -PyAPI_FUNC(void) PyErr_SyntaxLocation( - const char *filename, /* decoded from the filesystem encoding */ - int lineno); -PyAPI_FUNC(void) PyErr_SyntaxLocationEx( - const char *filename, /* decoded from the filesystem encoding */ - int lineno, - int col_offset); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyErr_SyntaxLocationObject( - PyObject *filename, - int lineno, - int col_offset); -#endif -PyAPI_FUNC(PyObject *) PyErr_ProgramText( - const char *filename, /* decoded from the filesystem encoding */ - int lineno); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( - PyObject *filename, - int lineno); -#endif - -/* The following functions are used to create and modify unicode - exceptions from C */ - -/* create a UnicodeDecodeError object */ -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_Create( - const char *encoding, /* UTF-8 encoded string */ - const char *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); - -/* create a UnicodeEncodeError object */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_Create( - const char *encoding, /* UTF-8 encoded string */ - const Py_UNICODE *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); -#endif - -/* create a UnicodeTranslateError object */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_Create( - const Py_UNICODE *object, - Py_ssize_t length, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(PyObject *) _PyUnicodeTranslateError_Create( - PyObject *object, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); -#endif - -/* get the encoding attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetEncoding(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetEncoding(PyObject *); - -/* get the object attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetObject(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetObject(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetObject(PyObject *); - -/* get the value of the start attribute (the int * may not be NULL) - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_GetStart(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeDecodeError_GetStart(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeTranslateError_GetStart(PyObject *, Py_ssize_t *); - -/* assign a new value to the start attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetStart(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetStart(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetStart(PyObject *, Py_ssize_t); - -/* get the value of the end attribute (the int *may not be NULL) - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_GetEnd(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeDecodeError_GetEnd(PyObject *, Py_ssize_t *); -PyAPI_FUNC(int) PyUnicodeTranslateError_GetEnd(PyObject *, Py_ssize_t *); - -/* assign a new value to the end attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetEnd(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetEnd(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetEnd(PyObject *, Py_ssize_t); - -/* get the value of the reason attribute */ -PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetReason(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetReason(PyObject *); -PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetReason(PyObject *); - -/* assign a new value to the reason attribute - return 0 on success, -1 on failure */ -PyAPI_FUNC(int) PyUnicodeEncodeError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(int) PyUnicodeDecodeError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); -PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason( - PyObject *exc, - const char *reason /* UTF-8 encoded string */ - ); - -/* These APIs aren't really part of the error implementation, but - often needed to format error messages; the native C lib APIs are - not available on all platforms, which is why we provide emulations - for those platforms in Python/mysnprintf.c, - WARNING: The return value of snprintf varies across platforms; do - not rely on any particular behavior; eventually the C99 defn may - be reliable. -*/ -#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF) -# define HAVE_SNPRINTF -# define snprintf _snprintf -# define vsnprintf _vsnprintf -#endif - -#include -PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 3, 4))); -PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) - Py_GCC_ATTRIBUTE((format(printf, 3, 0))); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_ERRORS_H */ +#ifndef Py_ERRORS_H +#define Py_ERRORS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Error objects */ + +#ifndef Py_LIMITED_API +/* PyException_HEAD defines the initial segment of every exception class. */ +#define PyException_HEAD PyObject_HEAD PyObject *dict;\ + PyObject *args; PyObject *traceback;\ + PyObject *context; PyObject *cause;\ + char suppress_context; + +typedef struct { + PyException_HEAD +} PyBaseExceptionObject; + +typedef struct { + PyException_HEAD + PyObject *msg; + PyObject *filename; + PyObject *lineno; + PyObject *offset; + PyObject *text; + PyObject *print_file_and_line; +} PySyntaxErrorObject; + +typedef struct { + PyException_HEAD + PyObject *msg; + PyObject *name; + PyObject *path; +} PyImportErrorObject; + +typedef struct { + PyException_HEAD + PyObject *encoding; + PyObject *object; + Py_ssize_t start; + Py_ssize_t end; + PyObject *reason; +} PyUnicodeErrorObject; + +typedef struct { + PyException_HEAD + PyObject *code; +} PySystemExitObject; + +typedef struct { + PyException_HEAD + PyObject *myerrno; + PyObject *strerror; + PyObject *filename; + PyObject *filename2; +#ifdef MS_WINDOWS + PyObject *winerror; +#endif + Py_ssize_t written; /* only for BlockingIOError, -1 otherwise */ +} PyOSErrorObject; + +typedef struct { + PyException_HEAD + PyObject *value; +} PyStopIterationObject; + +/* Compatibility typedefs */ +typedef PyOSErrorObject PyEnvironmentErrorObject; +#ifdef MS_WINDOWS +typedef PyOSErrorObject PyWindowsErrorObject; +#endif +#endif /* !Py_LIMITED_API */ + +/* Error handling definitions */ + +PyAPI_FUNC(void) PyErr_SetNone(PyObject *); +PyAPI_FUNC(void) PyErr_SetObject(PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); +#endif +PyAPI_FUNC(void) PyErr_SetString( + PyObject *exception, + const char *string /* decoded from utf-8 */ + ); +PyAPI_FUNC(PyObject *) PyErr_Occurred(void); +PyAPI_FUNC(void) PyErr_Clear(void); +PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); +PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); +PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); + +#if defined(__clang__) || \ + (defined(__GNUC_MAJOR__) && \ + ((__GNUC_MAJOR__ >= 3) || \ + (__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5))) +#define _Py_NO_RETURN __attribute__((__noreturn__)) +#else +#define _Py_NO_RETURN +#endif + +/* Defined in Python/pylifecycle.c */ +PyAPI_FUNC(void) Py_FatalError(const char *message) _Py_NO_RETURN; + +#if defined(Py_DEBUG) || defined(Py_LIMITED_API) +#define _PyErr_OCCURRED() PyErr_Occurred() +#else +#define _PyErr_OCCURRED() (PyThreadState_GET()->curexc_type) +#endif + +/* Error testing and normalization */ +PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); +PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); +PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); + +/* Traceback manipulation (PEP 3134) */ +PyAPI_FUNC(int) PyException_SetTraceback(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *); + +/* Cause manipulation (PEP 3134) */ +PyAPI_FUNC(PyObject *) PyException_GetCause(PyObject *); +PyAPI_FUNC(void) PyException_SetCause(PyObject *, PyObject *); + +/* Context manipulation (PEP 3134) */ +PyAPI_FUNC(PyObject *) PyException_GetContext(PyObject *); +PyAPI_FUNC(void) PyException_SetContext(PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); +#endif + +/* */ + +#define PyExceptionClass_Check(x) \ + (PyType_Check((x)) && \ + PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)) + +#define PyExceptionInstance_Check(x) \ + PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS) + +#define PyExceptionClass_Name(x) \ + ((char *)(((PyTypeObject*)(x))->tp_name)) + +#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type)) + + +/* Predefined exceptions */ + +PyAPI_DATA(PyObject *) PyExc_BaseException; +PyAPI_DATA(PyObject *) PyExc_Exception; +PyAPI_DATA(PyObject *) PyExc_StopAsyncIteration; +PyAPI_DATA(PyObject *) PyExc_StopIteration; +PyAPI_DATA(PyObject *) PyExc_GeneratorExit; +PyAPI_DATA(PyObject *) PyExc_ArithmeticError; +PyAPI_DATA(PyObject *) PyExc_LookupError; + +PyAPI_DATA(PyObject *) PyExc_AssertionError; +PyAPI_DATA(PyObject *) PyExc_AttributeError; +PyAPI_DATA(PyObject *) PyExc_BufferError; +PyAPI_DATA(PyObject *) PyExc_EOFError; +PyAPI_DATA(PyObject *) PyExc_FloatingPointError; +PyAPI_DATA(PyObject *) PyExc_OSError; +PyAPI_DATA(PyObject *) PyExc_ImportError; +PyAPI_DATA(PyObject *) PyExc_IndexError; +PyAPI_DATA(PyObject *) PyExc_KeyError; +PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; +PyAPI_DATA(PyObject *) PyExc_MemoryError; +PyAPI_DATA(PyObject *) PyExc_NameError; +PyAPI_DATA(PyObject *) PyExc_OverflowError; +PyAPI_DATA(PyObject *) PyExc_RuntimeError; +PyAPI_DATA(PyObject *) PyExc_RecursionError; +PyAPI_DATA(PyObject *) PyExc_NotImplementedError; +PyAPI_DATA(PyObject *) PyExc_SyntaxError; +PyAPI_DATA(PyObject *) PyExc_IndentationError; +PyAPI_DATA(PyObject *) PyExc_TabError; +PyAPI_DATA(PyObject *) PyExc_ReferenceError; +PyAPI_DATA(PyObject *) PyExc_SystemError; +PyAPI_DATA(PyObject *) PyExc_SystemExit; +PyAPI_DATA(PyObject *) PyExc_TypeError; +PyAPI_DATA(PyObject *) PyExc_UnboundLocalError; +PyAPI_DATA(PyObject *) PyExc_UnicodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeEncodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError; +PyAPI_DATA(PyObject *) PyExc_ValueError; +PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError; + +PyAPI_DATA(PyObject *) PyExc_BlockingIOError; +PyAPI_DATA(PyObject *) PyExc_BrokenPipeError; +PyAPI_DATA(PyObject *) PyExc_ChildProcessError; +PyAPI_DATA(PyObject *) PyExc_ConnectionError; +PyAPI_DATA(PyObject *) PyExc_ConnectionAbortedError; +PyAPI_DATA(PyObject *) PyExc_ConnectionRefusedError; +PyAPI_DATA(PyObject *) PyExc_ConnectionResetError; +PyAPI_DATA(PyObject *) PyExc_FileExistsError; +PyAPI_DATA(PyObject *) PyExc_FileNotFoundError; +PyAPI_DATA(PyObject *) PyExc_InterruptedError; +PyAPI_DATA(PyObject *) PyExc_IsADirectoryError; +PyAPI_DATA(PyObject *) PyExc_NotADirectoryError; +PyAPI_DATA(PyObject *) PyExc_PermissionError; +PyAPI_DATA(PyObject *) PyExc_ProcessLookupError; +PyAPI_DATA(PyObject *) PyExc_TimeoutError; + + +/* Compatibility aliases */ +PyAPI_DATA(PyObject *) PyExc_EnvironmentError; +PyAPI_DATA(PyObject *) PyExc_IOError; +#ifdef MS_WINDOWS +PyAPI_DATA(PyObject *) PyExc_WindowsError; +#endif + +PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst; + +/* Predefined warning categories */ +PyAPI_DATA(PyObject *) PyExc_Warning; +PyAPI_DATA(PyObject *) PyExc_UserWarning; +PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; +PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; +PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; +PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; +PyAPI_DATA(PyObject *) PyExc_FutureWarning; +PyAPI_DATA(PyObject *) PyExc_ImportWarning; +PyAPI_DATA(PyObject *) PyExc_UnicodeWarning; +PyAPI_DATA(PyObject *) PyExc_BytesWarning; +PyAPI_DATA(PyObject *) PyExc_ResourceWarning; + + +/* Convenience functions */ + +PyAPI_FUNC(int) PyErr_BadArgument(void); +PyAPI_FUNC(PyObject *) PyErr_NoMemory(void); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrno(PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObject( + PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObjects( + PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilename( + PyObject *exc, + const char *filename /* decoded from the filesystem encoding */ + ); +#if defined(MS_WINDOWS) && !defined(Py_LIMITED_API) +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename( + PyObject *, const Py_UNICODE *); +#endif /* MS_WINDOWS */ + +PyAPI_FUNC(PyObject *) PyErr_Format( + PyObject *exception, + const char *format, /* ASCII-encoded string */ + ... + ); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +PyAPI_FUNC(PyObject *) PyErr_FormatV( + PyObject *exception, + const char *format, + va_list vargs); +#endif + +#ifdef MS_WINDOWS +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( + int ierr, + const char *filename /* decoded from the filesystem encoding */ + ); +#ifndef Py_LIMITED_API +/* XXX redeclare to use WSTRING */ +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename( + int, const Py_UNICODE *); +#endif +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int); +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject( + PyObject *,int, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObjects( + PyObject *,int, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename( + PyObject *exc, + int ierr, + const char *filename /* decoded from the filesystem encoding */ + ); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename( + PyObject *,int, const Py_UNICODE *); +#endif +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); +#endif /* MS_WINDOWS */ + +PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, + PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, + PyObject *); + +/* Export the old function so that the existing API remains available: */ +PyAPI_FUNC(void) PyErr_BadInternalCall(void); +PyAPI_FUNC(void) _PyErr_BadInternalCall(const char *filename, int lineno); +/* Mask the old API with a call to the new API for code compiled under + Python 2.0: */ +#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) + +/* Function to create a new exception */ +PyAPI_FUNC(PyObject *) PyErr_NewException( + const char *name, PyObject *base, PyObject *dict); +PyAPI_FUNC(PyObject *) PyErr_NewExceptionWithDoc( + const char *name, const char *doc, PyObject *base, PyObject *dict); +PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *); + +/* In exceptions.c */ +#ifndef Py_LIMITED_API +/* Helper that attempts to replace the current exception with one of the + * same type but with a prefix added to the exception text. The resulting + * exception description looks like: + * + * prefix (exc_type: original_exc_str) + * + * Only some exceptions can be safely replaced. If the function determines + * it isn't safe to perform the replacement, it will leave the original + * unmodified exception in place. + * + * Returns a borrowed reference to the new exception (if any), NULL if the + * existing exception was left in place. + */ +PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( + const char *prefix_format, /* ASCII-encoded string */ + ... + ); +#endif + + +/* In sigcheck.c or signalmodule.c */ +PyAPI_FUNC(int) PyErr_CheckSignals(void); +PyAPI_FUNC(void) PyErr_SetInterrupt(void); + +/* In signalmodule.c */ +#ifndef Py_LIMITED_API +int PySignal_SetWakeupFd(int fd); +#endif + +/* Support for adding program text to SyntaxErrors */ +PyAPI_FUNC(void) PyErr_SyntaxLocation( + const char *filename, /* decoded from the filesystem encoding */ + int lineno); +PyAPI_FUNC(void) PyErr_SyntaxLocationEx( + const char *filename, /* decoded from the filesystem encoding */ + int lineno, + int col_offset); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) PyErr_SyntaxLocationObject( + PyObject *filename, + int lineno, + int col_offset); +#endif +PyAPI_FUNC(PyObject *) PyErr_ProgramText( + const char *filename, /* decoded from the filesystem encoding */ + int lineno); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( + PyObject *filename, + int lineno); +#endif + +/* The following functions are used to create and modify unicode + exceptions from C */ + +/* create a UnicodeDecodeError object */ +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_Create( + const char *encoding, /* UTF-8 encoded string */ + const char *object, + Py_ssize_t length, + Py_ssize_t start, + Py_ssize_t end, + const char *reason /* UTF-8 encoded string */ + ); + +/* create a UnicodeEncodeError object */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_Create( + const char *encoding, /* UTF-8 encoded string */ + const Py_UNICODE *object, + Py_ssize_t length, + Py_ssize_t start, + Py_ssize_t end, + const char *reason /* UTF-8 encoded string */ + ); +#endif + +/* create a UnicodeTranslateError object */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_Create( + const Py_UNICODE *object, + Py_ssize_t length, + Py_ssize_t start, + Py_ssize_t end, + const char *reason /* UTF-8 encoded string */ + ); +PyAPI_FUNC(PyObject *) _PyUnicodeTranslateError_Create( + PyObject *object, + Py_ssize_t start, + Py_ssize_t end, + const char *reason /* UTF-8 encoded string */ + ); +#endif + +/* get the encoding attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetEncoding(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetEncoding(PyObject *); + +/* get the object attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetObject(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetObject(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetObject(PyObject *); + +/* get the value of the start attribute (the int * may not be NULL) + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_GetStart(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeDecodeError_GetStart(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeTranslateError_GetStart(PyObject *, Py_ssize_t *); + +/* assign a new value to the start attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetStart(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetStart(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetStart(PyObject *, Py_ssize_t); + +/* get the value of the end attribute (the int *may not be NULL) + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_GetEnd(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeDecodeError_GetEnd(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeTranslateError_GetEnd(PyObject *, Py_ssize_t *); + +/* assign a new value to the end attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetEnd(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetEnd(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetEnd(PyObject *, Py_ssize_t); + +/* get the value of the reason attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetReason(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetReason(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetReason(PyObject *); + +/* assign a new value to the reason attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetReason( + PyObject *exc, + const char *reason /* UTF-8 encoded string */ + ); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetReason( + PyObject *exc, + const char *reason /* UTF-8 encoded string */ + ); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason( + PyObject *exc, + const char *reason /* UTF-8 encoded string */ + ); + +/* These APIs aren't really part of the error implementation, but + often needed to format error messages; the native C lib APIs are + not available on all platforms, which is why we provide emulations + for those platforms in Python/mysnprintf.c, + WARNING: The return value of snprintf varies across platforms; do + not rely on any particular behavior; eventually the C99 defn may + be reliable. +*/ +#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF) +# define HAVE_SNPRINTF +# define snprintf _snprintf +# define vsnprintf _vsnprintf +#endif + +#include +PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 3, 4))); +PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) + Py_GCC_ATTRIBUTE((format(printf, 3, 0))); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ERRORS_H */ diff --git a/libs/nxpy/include/pyexpat.h b/libs/nxpy/include/pyexpat.h index 44259bf6..ff237765 100644 --- a/libs/nxpy/include/pyexpat.h +++ b/libs/nxpy/include/pyexpat.h @@ -1,53 +1,53 @@ -/* Stuff to export relevant 'expat' entry points from pyexpat to other - * parser modules, such as cElementTree. */ - -/* note: you must import expat.h before importing this module! */ - -#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" -#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" - -struct PyExpat_CAPI -{ - char* magic; /* set to PyExpat_CAPI_MAGIC */ - int size; /* set to sizeof(struct PyExpat_CAPI) */ - int MAJOR_VERSION; - int MINOR_VERSION; - int MICRO_VERSION; - /* pointers to selected expat functions. add new functions at - the end, if needed */ - const XML_LChar * (*ErrorString)(enum XML_Error code); - enum XML_Error (*GetErrorCode)(XML_Parser parser); - XML_Size (*GetErrorColumnNumber)(XML_Parser parser); - XML_Size (*GetErrorLineNumber)(XML_Parser parser); - enum XML_Status (*Parse)( - XML_Parser parser, const char *s, int len, int isFinal); - XML_Parser (*ParserCreate_MM)( - const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, - const XML_Char *namespaceSeparator); - void (*ParserFree)(XML_Parser parser); - void (*SetCharacterDataHandler)( - XML_Parser parser, XML_CharacterDataHandler handler); - void (*SetCommentHandler)( - XML_Parser parser, XML_CommentHandler handler); - void (*SetDefaultHandlerExpand)( - XML_Parser parser, XML_DefaultHandler handler); - void (*SetElementHandler)( - XML_Parser parser, XML_StartElementHandler start, - XML_EndElementHandler end); - void (*SetNamespaceDeclHandler)( - XML_Parser parser, XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end); - void (*SetProcessingInstructionHandler)( - XML_Parser parser, XML_ProcessingInstructionHandler handler); - void (*SetUnknownEncodingHandler)( - XML_Parser parser, XML_UnknownEncodingHandler handler, - void *encodingHandlerData); - void (*SetUserData)(XML_Parser parser, void *userData); - void (*SetStartDoctypeDeclHandler)(XML_Parser parser, - XML_StartDoctypeDeclHandler start); - enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); - int (*DefaultUnknownEncodingHandler)( - void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); - /* always add new stuff to the end! */ -}; - +/* Stuff to export relevant 'expat' entry points from pyexpat to other + * parser modules, such as cElementTree. */ + +/* note: you must import expat.h before importing this module! */ + +#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" +#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" + +struct PyExpat_CAPI +{ + char* magic; /* set to PyExpat_CAPI_MAGIC */ + int size; /* set to sizeof(struct PyExpat_CAPI) */ + int MAJOR_VERSION; + int MINOR_VERSION; + int MICRO_VERSION; + /* pointers to selected expat functions. add new functions at + the end, if needed */ + const XML_LChar * (*ErrorString)(enum XML_Error code); + enum XML_Error (*GetErrorCode)(XML_Parser parser); + XML_Size (*GetErrorColumnNumber)(XML_Parser parser); + XML_Size (*GetErrorLineNumber)(XML_Parser parser); + enum XML_Status (*Parse)( + XML_Parser parser, const char *s, int len, int isFinal); + XML_Parser (*ParserCreate_MM)( + const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + void (*ParserFree)(XML_Parser parser); + void (*SetCharacterDataHandler)( + XML_Parser parser, XML_CharacterDataHandler handler); + void (*SetCommentHandler)( + XML_Parser parser, XML_CommentHandler handler); + void (*SetDefaultHandlerExpand)( + XML_Parser parser, XML_DefaultHandler handler); + void (*SetElementHandler)( + XML_Parser parser, XML_StartElementHandler start, + XML_EndElementHandler end); + void (*SetNamespaceDeclHandler)( + XML_Parser parser, XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + void (*SetProcessingInstructionHandler)( + XML_Parser parser, XML_ProcessingInstructionHandler handler); + void (*SetUnknownEncodingHandler)( + XML_Parser parser, XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + void (*SetUserData)(XML_Parser parser, void *userData); + void (*SetStartDoctypeDeclHandler)(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); + int (*DefaultUnknownEncodingHandler)( + void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); + /* always add new stuff to the end! */ +}; + diff --git a/libs/nxpy/include/pyfpe.h b/libs/nxpy/include/pyfpe.h index f9a15e62..0793d9eb 100644 --- a/libs/nxpy/include/pyfpe.h +++ b/libs/nxpy/include/pyfpe.h @@ -1,176 +1,176 @@ -#ifndef Py_PYFPE_H -#define Py_PYFPE_H -#ifdef __cplusplus -extern "C" { -#endif -/* - --------------------------------------------------------------------- - / Copyright (c) 1996. \ - | The Regents of the University of California. | - | All rights reserved. | - | | - | Permission to use, copy, modify, and distribute this software for | - | any purpose without fee is hereby granted, provided that this en- | - | tire notice is included in all copies of any software which is or | - | includes a copy or modification of this software and in all | - | copies of the supporting documentation for such software. | - | | - | This work was produced at the University of California, Lawrence | - | Livermore National Laboratory under contract no. W-7405-ENG-48 | - | between the U.S. Department of Energy and The Regents of the | - | University of California for the operation of UC LLNL. | - | | - | DISCLAIMER | - | | - | This software was prepared as an account of work sponsored by an | - | agency of the United States Government. Neither the United States | - | Government nor the University of California nor any of their em- | - | ployees, makes any warranty, express or implied, or assumes any | - | liability or responsibility for the accuracy, completeness, or | - | usefulness of any information, apparatus, product, or process | - | disclosed, or represents that its use would not infringe | - | privately-owned rights. Reference herein to any specific commer- | - | cial products, process, or service by trade name, trademark, | - | manufacturer, or otherwise, does not necessarily constitute or | - | imply its endorsement, recommendation, or favoring by the United | - | States Government or the University of California. The views and | - | opinions of authors expressed herein do not necessarily state or | - | reflect those of the United States Government or the University | - | of California, and shall not be used for advertising or product | - \ endorsement purposes. / - --------------------------------------------------------------------- -*/ - -/* - * Define macros for handling SIGFPE. - * Lee Busby, LLNL, November, 1996 - * busby1@llnl.gov - * - ********************************************* - * Overview of the system for handling SIGFPE: - * - * This file (Include/pyfpe.h) defines a couple of "wrapper" macros for - * insertion into your Python C code of choice. Their proper use is - * discussed below. The file Python/pyfpe.c defines a pair of global - * variables PyFPE_jbuf and PyFPE_counter which are used by the signal - * handler for SIGFPE to decide if a particular exception was protected - * by the macros. The signal handler itself, and code for enabling the - * generation of SIGFPE in the first place, is in a (new) Python module - * named fpectl. This module is standard in every respect. It can be loaded - * either statically or dynamically as you choose, and like any other - * Python module, has no effect until you import it. - * - * In the general case, there are three steps toward handling SIGFPE in any - * Python code: - * - * 1) Add the *_PROTECT macros to your C code as required to protect - * dangerous floating point sections. - * - * 2) Turn on the inclusion of the code by adding the ``--with-fpectl'' - * flag at the time you run configure. If the fpectl or other modules - * which use the *_PROTECT macros are to be dynamically loaded, be - * sure they are compiled with WANT_SIGFPE_HANDLER defined. - * - * 3) When python is built and running, import fpectl, and execute - * fpectl.turnon_sigfpe(). This sets up the signal handler and enables - * generation of SIGFPE whenever an exception occurs. From this point - * on, any properly trapped SIGFPE should result in the Python - * FloatingPointError exception. - * - * Step 1 has been done already for the Python kernel code, and should be - * done soon for the NumPy array package. Step 2 is usually done once at - * python install time. Python's behavior with respect to SIGFPE is not - * changed unless you also do step 3. Thus you can control this new - * facility at compile time, or run time, or both. - * - ******************************** - * Using the macros in your code: - * - * static PyObject *foobar(PyObject *self,PyObject *args) - * { - * .... - * PyFPE_START_PROTECT("Error in foobar", return 0) - * result = dangerous_op(somearg1, somearg2, ...); - * PyFPE_END_PROTECT(result) - * .... - * } - * - * If a floating point error occurs in dangerous_op, foobar returns 0 (NULL), - * after setting the associated value of the FloatingPointError exception to - * "Error in foobar". ``Dangerous_op'' can be a single operation, or a block - * of code, function calls, or any combination, so long as no alternate - * return is possible before the PyFPE_END_PROTECT macro is reached. - * - * The macros can only be used in a function context where an error return - * can be recognized as signaling a Python exception. (Generally, most - * functions that return a PyObject * will qualify.) - * - * Guido's original design suggestion for PyFPE_START_PROTECT and - * PyFPE_END_PROTECT had them open and close a local block, with a locally - * defined jmp_buf and jmp_buf pointer. This would allow recursive nesting - * of the macros. The Ansi C standard makes it clear that such local - * variables need to be declared with the "volatile" type qualifier to keep - * setjmp from corrupting their values. Some current implementations seem - * to be more restrictive. For example, the HPUX man page for setjmp says - * - * Upon the return from a setjmp() call caused by a longjmp(), the - * values of any non-static local variables belonging to the routine - * from which setjmp() was called are undefined. Code which depends on - * such values is not guaranteed to be portable. - * - * I therefore decided on a more limited form of nesting, using a counter - * variable (PyFPE_counter) to keep track of any recursion. If an exception - * occurs in an ``inner'' pair of macros, the return will apparently - * come from the outermost level. - * - */ - -#ifdef WANT_SIGFPE_HANDLER -#include -#include -#include -extern jmp_buf PyFPE_jbuf; -extern int PyFPE_counter; -extern double PyFPE_dummy(void *); - -#define PyFPE_START_PROTECT(err_string, leave_stmt) \ -if (!PyFPE_counter++ && setjmp(PyFPE_jbuf)) { \ - PyErr_SetString(PyExc_FloatingPointError, err_string); \ - PyFPE_counter = 0; \ - leave_stmt; \ -} - -/* - * This (following) is a heck of a way to decrement a counter. However, - * unless the macro argument is provided, code optimizers will sometimes move - * this statement so that it gets executed *before* the unsafe expression - * which we're trying to protect. That pretty well messes things up, - * of course. - * - * If the expression(s) you're trying to protect don't happen to return a - * value, you will need to manufacture a dummy result just to preserve the - * correct ordering of statements. Note that the macro passes the address - * of its argument (so you need to give it something which is addressable). - * If your expression returns multiple results, pass the last such result - * to PyFPE_END_PROTECT. - * - * Note that PyFPE_dummy returns a double, which is cast to int. - * This seeming insanity is to tickle the Floating Point Unit (FPU). - * If an exception has occurred in a preceding floating point operation, - * some architectures (notably Intel 80x86) will not deliver the interrupt - * until the *next* floating point operation. This is painful if you've - * already decremented PyFPE_counter. - */ -#define PyFPE_END_PROTECT(v) PyFPE_counter -= (int)PyFPE_dummy(&(v)); - -#else - -#define PyFPE_START_PROTECT(err_string, leave_stmt) -#define PyFPE_END_PROTECT(v) - -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYFPE_H */ +#ifndef Py_PYFPE_H +#define Py_PYFPE_H +#ifdef __cplusplus +extern "C" { +#endif +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + * Define macros for handling SIGFPE. + * Lee Busby, LLNL, November, 1996 + * busby1@llnl.gov + * + ********************************************* + * Overview of the system for handling SIGFPE: + * + * This file (Include/pyfpe.h) defines a couple of "wrapper" macros for + * insertion into your Python C code of choice. Their proper use is + * discussed below. The file Python/pyfpe.c defines a pair of global + * variables PyFPE_jbuf and PyFPE_counter which are used by the signal + * handler for SIGFPE to decide if a particular exception was protected + * by the macros. The signal handler itself, and code for enabling the + * generation of SIGFPE in the first place, is in a (new) Python module + * named fpectl. This module is standard in every respect. It can be loaded + * either statically or dynamically as you choose, and like any other + * Python module, has no effect until you import it. + * + * In the general case, there are three steps toward handling SIGFPE in any + * Python code: + * + * 1) Add the *_PROTECT macros to your C code as required to protect + * dangerous floating point sections. + * + * 2) Turn on the inclusion of the code by adding the ``--with-fpectl'' + * flag at the time you run configure. If the fpectl or other modules + * which use the *_PROTECT macros are to be dynamically loaded, be + * sure they are compiled with WANT_SIGFPE_HANDLER defined. + * + * 3) When python is built and running, import fpectl, and execute + * fpectl.turnon_sigfpe(). This sets up the signal handler and enables + * generation of SIGFPE whenever an exception occurs. From this point + * on, any properly trapped SIGFPE should result in the Python + * FloatingPointError exception. + * + * Step 1 has been done already for the Python kernel code, and should be + * done soon for the NumPy array package. Step 2 is usually done once at + * python install time. Python's behavior with respect to SIGFPE is not + * changed unless you also do step 3. Thus you can control this new + * facility at compile time, or run time, or both. + * + ******************************** + * Using the macros in your code: + * + * static PyObject *foobar(PyObject *self,PyObject *args) + * { + * .... + * PyFPE_START_PROTECT("Error in foobar", return 0) + * result = dangerous_op(somearg1, somearg2, ...); + * PyFPE_END_PROTECT(result) + * .... + * } + * + * If a floating point error occurs in dangerous_op, foobar returns 0 (NULL), + * after setting the associated value of the FloatingPointError exception to + * "Error in foobar". ``Dangerous_op'' can be a single operation, or a block + * of code, function calls, or any combination, so long as no alternate + * return is possible before the PyFPE_END_PROTECT macro is reached. + * + * The macros can only be used in a function context where an error return + * can be recognized as signaling a Python exception. (Generally, most + * functions that return a PyObject * will qualify.) + * + * Guido's original design suggestion for PyFPE_START_PROTECT and + * PyFPE_END_PROTECT had them open and close a local block, with a locally + * defined jmp_buf and jmp_buf pointer. This would allow recursive nesting + * of the macros. The Ansi C standard makes it clear that such local + * variables need to be declared with the "volatile" type qualifier to keep + * setjmp from corrupting their values. Some current implementations seem + * to be more restrictive. For example, the HPUX man page for setjmp says + * + * Upon the return from a setjmp() call caused by a longjmp(), the + * values of any non-static local variables belonging to the routine + * from which setjmp() was called are undefined. Code which depends on + * such values is not guaranteed to be portable. + * + * I therefore decided on a more limited form of nesting, using a counter + * variable (PyFPE_counter) to keep track of any recursion. If an exception + * occurs in an ``inner'' pair of macros, the return will apparently + * come from the outermost level. + * + */ + +#ifdef WANT_SIGFPE_HANDLER +#include +#include +#include +extern jmp_buf PyFPE_jbuf; +extern int PyFPE_counter; +extern double PyFPE_dummy(void *); + +#define PyFPE_START_PROTECT(err_string, leave_stmt) \ +if (!PyFPE_counter++ && setjmp(PyFPE_jbuf)) { \ + PyErr_SetString(PyExc_FloatingPointError, err_string); \ + PyFPE_counter = 0; \ + leave_stmt; \ +} + +/* + * This (following) is a heck of a way to decrement a counter. However, + * unless the macro argument is provided, code optimizers will sometimes move + * this statement so that it gets executed *before* the unsafe expression + * which we're trying to protect. That pretty well messes things up, + * of course. + * + * If the expression(s) you're trying to protect don't happen to return a + * value, you will need to manufacture a dummy result just to preserve the + * correct ordering of statements. Note that the macro passes the address + * of its argument (so you need to give it something which is addressable). + * If your expression returns multiple results, pass the last such result + * to PyFPE_END_PROTECT. + * + * Note that PyFPE_dummy returns a double, which is cast to int. + * This seeming insanity is to tickle the Floating Point Unit (FPU). + * If an exception has occurred in a preceding floating point operation, + * some architectures (notably Intel 80x86) will not deliver the interrupt + * until the *next* floating point operation. This is painful if you've + * already decremented PyFPE_counter. + */ +#define PyFPE_END_PROTECT(v) PyFPE_counter -= (int)PyFPE_dummy(&(v)); + +#else + +#define PyFPE_START_PROTECT(err_string, leave_stmt) +#define PyFPE_END_PROTECT(v) + +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYFPE_H */ diff --git a/libs/nxpy/include/pygetopt.h b/libs/nxpy/include/pygetopt.h index 425c7dd6..482d231e 100644 --- a/libs/nxpy/include/pygetopt.h +++ b/libs/nxpy/include/pygetopt.h @@ -1,21 +1,21 @@ - -#ifndef Py_PYGETOPT_H -#define Py_PYGETOPT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_DATA(int) _PyOS_opterr; -PyAPI_DATA(int) _PyOS_optind; -PyAPI_DATA(wchar_t *) _PyOS_optarg; - -PyAPI_FUNC(void) _PyOS_ResetGetOpt(void); -#endif - -PyAPI_FUNC(int) _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYGETOPT_H */ + +#ifndef Py_PYGETOPT_H +#define Py_PYGETOPT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +PyAPI_DATA(int) _PyOS_opterr; +PyAPI_DATA(int) _PyOS_optind; +PyAPI_DATA(wchar_t *) _PyOS_optarg; + +PyAPI_FUNC(void) _PyOS_ResetGetOpt(void); +#endif + +PyAPI_FUNC(int) _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYGETOPT_H */ diff --git a/libs/nxpy/include/pyhash.h b/libs/nxpy/include/pyhash.h index a7ca9375..e6e7b832 100644 --- a/libs/nxpy/include/pyhash.h +++ b/libs/nxpy/include/pyhash.h @@ -1,149 +1,149 @@ -#ifndef Py_HASH_H - -#define Py_HASH_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Helpers for hash functions */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_hash_t) _Py_HashDouble(double); -PyAPI_FUNC(Py_hash_t) _Py_HashPointer(void*); -PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void*, Py_ssize_t); -#endif - -/* Prime multiplier used in string and various other hashes. */ -#define _PyHASH_MULTIPLIER 1000003UL /* 0xf4243 */ - -/* Parameters used for the numeric hash implementation. See notes for - _Py_HashDouble in Objects/object.c. Numeric hashes are based on - reduction modulo the prime 2**_PyHASH_BITS - 1. */ - -#if SIZEOF_VOID_P >= 8 -# define _PyHASH_BITS 61 -#else -# define _PyHASH_BITS 31 -#endif - -#define _PyHASH_MODULUS (((size_t)1 << _PyHASH_BITS) - 1) -#define _PyHASH_INF 314159 -#define _PyHASH_NAN 0 -#define _PyHASH_IMAG _PyHASH_MULTIPLIER - - -/* hash secret - * - * memory layout on 64 bit systems - * cccccccc cccccccc cccccccc uc -- unsigned char[24] - * pppppppp ssssssss ........ fnv -- two Py_hash_t - * k0k0k0k0 k1k1k1k1 ........ siphash -- two PY_UINT64_T - * ........ ........ ssssssss djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeeeeeee pyexpat XML hash salt - * - * memory layout on 32 bit systems - * cccccccc cccccccc cccccccc uc - * ppppssss ........ ........ fnv -- two Py_hash_t - * k0k0k0k0 k1k1k1k1 ........ siphash -- two PY_UINT64_T (*) - * ........ ........ ssss.... djbx33a -- 16 bytes padding + one Py_hash_t - * ........ ........ eeee.... pyexpat XML hash salt - * - * (*) The siphash member may not be available on 32 bit platforms without - * an unsigned int64 data type. - */ -#ifndef Py_LIMITED_API -typedef union { - /* ensure 24 bytes */ - unsigned char uc[24]; - /* two Py_hash_t for FNV */ - struct { - Py_hash_t prefix; - Py_hash_t suffix; - } fnv; -#ifdef PY_UINT64_T - /* two uint64 for SipHash24 */ - struct { - PY_UINT64_T k0; - PY_UINT64_T k1; - } siphash; -#endif - /* a different (!) Py_hash_t for small string optimization */ - struct { - unsigned char padding[16]; - Py_hash_t suffix; - } djbx33a; - struct { - unsigned char padding[16]; - Py_hash_t hashsalt; - } expat; -} _Py_HashSecret_t; -PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; -#endif - -#ifdef Py_DEBUG -PyAPI_DATA(int) _Py_HashSecret_Initialized; -#endif - - -/* hash function definition */ -#ifndef Py_LIMITED_API -typedef struct { - Py_hash_t (*const hash)(const void *, Py_ssize_t); - const char *name; - const int hash_bits; - const int seed_bits; -} PyHash_FuncDef; - -PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); -#endif - - -/* cutoff for small string DJBX33A optimization in range [1, cutoff). - * - * About 50% of the strings in a typical Python application are smaller than - * 6 to 7 chars. However DJBX33A is vulnerable to hash collision attacks. - * NEVER use DJBX33A for long strings! - * - * A Py_HASH_CUTOFF of 0 disables small string optimization. 32 bit platforms - * should use a smaller cutoff because it is easier to create colliding - * strings. A cutoff of 7 on 64bit platforms and 5 on 32bit platforms should - * provide a decent safety margin. - */ -#ifndef Py_HASH_CUTOFF -# define Py_HASH_CUTOFF 0 -#elif (Py_HASH_CUTOFF > 7 || Py_HASH_CUTOFF < 0) -# error Py_HASH_CUTOFF must in range 0...7. -#endif /* Py_HASH_CUTOFF */ - - -/* hash algorithm selection - * - * The values for Py_HASH_SIPHASH24 and Py_HASH_FNV are hard-coded in the - * configure script. - * - * - FNV is available on all platforms and architectures. - * - SIPHASH24 only works on plaforms that provide PY_UINT64_T and doesn't - * require aligned memory for integers. - * - With EXTERNAL embedders can provide an alternative implementation with:: - * - * PyHash_FuncDef PyHash_Func = {...}; - * - * XXX: Figure out __declspec() for extern PyHash_FuncDef. - */ -#define Py_HASH_EXTERNAL 0 -#define Py_HASH_SIPHASH24 1 -#define Py_HASH_FNV 2 - -#ifndef Py_HASH_ALGORITHM -# if (defined(PY_UINT64_T) && defined(PY_UINT32_T) \ - && !defined(HAVE_ALIGNED_REQUIRED)) -# define Py_HASH_ALGORITHM Py_HASH_SIPHASH24 -# else -# define Py_HASH_ALGORITHM Py_HASH_FNV -# endif /* uint64_t && uint32_t && aligned */ -#endif /* Py_HASH_ALGORITHM */ - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_HASH_H */ +#ifndef Py_HASH_H + +#define Py_HASH_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Helpers for hash functions */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_hash_t) _Py_HashDouble(double); +PyAPI_FUNC(Py_hash_t) _Py_HashPointer(void*); +PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void*, Py_ssize_t); +#endif + +/* Prime multiplier used in string and various other hashes. */ +#define _PyHASH_MULTIPLIER 1000003UL /* 0xf4243 */ + +/* Parameters used for the numeric hash implementation. See notes for + _Py_HashDouble in Objects/object.c. Numeric hashes are based on + reduction modulo the prime 2**_PyHASH_BITS - 1. */ + +#if SIZEOF_VOID_P >= 8 +# define _PyHASH_BITS 61 +#else +# define _PyHASH_BITS 31 +#endif + +#define _PyHASH_MODULUS (((size_t)1 << _PyHASH_BITS) - 1) +#define _PyHASH_INF 314159 +#define _PyHASH_NAN 0 +#define _PyHASH_IMAG _PyHASH_MULTIPLIER + + +/* hash secret + * + * memory layout on 64 bit systems + * cccccccc cccccccc cccccccc uc -- unsigned char[24] + * pppppppp ssssssss ........ fnv -- two Py_hash_t + * k0k0k0k0 k1k1k1k1 ........ siphash -- two PY_UINT64_T + * ........ ........ ssssssss djbx33a -- 16 bytes padding + one Py_hash_t + * ........ ........ eeeeeeee pyexpat XML hash salt + * + * memory layout on 32 bit systems + * cccccccc cccccccc cccccccc uc + * ppppssss ........ ........ fnv -- two Py_hash_t + * k0k0k0k0 k1k1k1k1 ........ siphash -- two PY_UINT64_T (*) + * ........ ........ ssss.... djbx33a -- 16 bytes padding + one Py_hash_t + * ........ ........ eeee.... pyexpat XML hash salt + * + * (*) The siphash member may not be available on 32 bit platforms without + * an unsigned int64 data type. + */ +#ifndef Py_LIMITED_API +typedef union { + /* ensure 24 bytes */ + unsigned char uc[24]; + /* two Py_hash_t for FNV */ + struct { + Py_hash_t prefix; + Py_hash_t suffix; + } fnv; +#ifdef PY_UINT64_T + /* two uint64 for SipHash24 */ + struct { + PY_UINT64_T k0; + PY_UINT64_T k1; + } siphash; +#endif + /* a different (!) Py_hash_t for small string optimization */ + struct { + unsigned char padding[16]; + Py_hash_t suffix; + } djbx33a; + struct { + unsigned char padding[16]; + Py_hash_t hashsalt; + } expat; +} _Py_HashSecret_t; +PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; +#endif + +#ifdef Py_DEBUG +PyAPI_DATA(int) _Py_HashSecret_Initialized; +#endif + + +/* hash function definition */ +#ifndef Py_LIMITED_API +typedef struct { + Py_hash_t (*const hash)(const void *, Py_ssize_t); + const char *name; + const int hash_bits; + const int seed_bits; +} PyHash_FuncDef; + +PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); +#endif + + +/* cutoff for small string DJBX33A optimization in range [1, cutoff). + * + * About 50% of the strings in a typical Python application are smaller than + * 6 to 7 chars. However DJBX33A is vulnerable to hash collision attacks. + * NEVER use DJBX33A for long strings! + * + * A Py_HASH_CUTOFF of 0 disables small string optimization. 32 bit platforms + * should use a smaller cutoff because it is easier to create colliding + * strings. A cutoff of 7 on 64bit platforms and 5 on 32bit platforms should + * provide a decent safety margin. + */ +#ifndef Py_HASH_CUTOFF +# define Py_HASH_CUTOFF 0 +#elif (Py_HASH_CUTOFF > 7 || Py_HASH_CUTOFF < 0) +# error Py_HASH_CUTOFF must in range 0...7. +#endif /* Py_HASH_CUTOFF */ + + +/* hash algorithm selection + * + * The values for Py_HASH_SIPHASH24 and Py_HASH_FNV are hard-coded in the + * configure script. + * + * - FNV is available on all platforms and architectures. + * - SIPHASH24 only works on plaforms that provide PY_UINT64_T and doesn't + * require aligned memory for integers. + * - With EXTERNAL embedders can provide an alternative implementation with:: + * + * PyHash_FuncDef PyHash_Func = {...}; + * + * XXX: Figure out __declspec() for extern PyHash_FuncDef. + */ +#define Py_HASH_EXTERNAL 0 +#define Py_HASH_SIPHASH24 1 +#define Py_HASH_FNV 2 + +#ifndef Py_HASH_ALGORITHM +# if (defined(PY_UINT64_T) && defined(PY_UINT32_T) \ + && !defined(HAVE_ALIGNED_REQUIRED)) +# define Py_HASH_ALGORITHM Py_HASH_SIPHASH24 +# else +# define Py_HASH_ALGORITHM Py_HASH_FNV +# endif /* uint64_t && uint32_t && aligned */ +#endif /* Py_HASH_ALGORITHM */ + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_HASH_H */ diff --git a/libs/nxpy/include/pylifecycle.h b/libs/nxpy/include/pylifecycle.h index ccdebe26..2b3b50c7 100644 --- a/libs/nxpy/include/pylifecycle.h +++ b/libs/nxpy/include/pylifecycle.h @@ -1,124 +1,124 @@ - -/* Interfaces to configure, query, create & destroy the Python runtime */ - -#ifndef Py_PYLIFECYCLE_H -#define Py_PYLIFECYCLE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); - -PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); - -#ifndef Py_LIMITED_API -/* Only used by applications that embed the interpreter and need to - * override the standard encoding determination mechanism - */ -PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, - const char *errors); -#endif - -PyAPI_FUNC(void) Py_Initialize(void); -PyAPI_FUNC(void) Py_InitializeEx(int); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int); -#endif -PyAPI_FUNC(void) Py_Finalize(void); -PyAPI_FUNC(int) Py_IsInitialized(void); -PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); -PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); - - -/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level - * exit functions. - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void)); -#endif -PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); - -PyAPI_FUNC(void) Py_Exit(int); - -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_RestoreSignals(void); - -PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); -#endif - -/* Bootstrap __main__ (defined in Modules/main.c) */ -PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); - -/* In getpath.c */ -PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); -PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetPath(void); -PyAPI_FUNC(void) Py_SetPath(const wchar_t *); -#ifdef MS_WINDOWS -int _Py_CheckPython3(); -#endif - -/* In their own files */ -PyAPI_FUNC(const char *) Py_GetVersion(void); -PyAPI_FUNC(const char *) Py_GetPlatform(void); -PyAPI_FUNC(const char *) Py_GetCopyright(void); -PyAPI_FUNC(const char *) Py_GetCompiler(void); -PyAPI_FUNC(const char *) Py_GetBuildInfo(void); -#ifndef Py_LIMITED_API -PyAPI_FUNC(const char *) _Py_hgidentifier(void); -PyAPI_FUNC(const char *) _Py_hgversion(void); -#endif - -/* Internal -- various one-time initializations */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); -PyAPI_FUNC(PyObject *) _PySys_Init(void); -PyAPI_FUNC(void) _PyImport_Init(void); -PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); -PyAPI_FUNC(void) _PyImportHooks_Init(void); -PyAPI_FUNC(int) _PyFrame_Init(void); -PyAPI_FUNC(int) _PyFloat_Init(void); -PyAPI_FUNC(int) PyByteArray_Init(void); -PyAPI_FUNC(void) _PyRandom_Init(void); -#endif - -/* Various internal finalizers */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyExc_Fini(void); -PyAPI_FUNC(void) _PyImport_Fini(void); -PyAPI_FUNC(void) PyMethod_Fini(void); -PyAPI_FUNC(void) PyFrame_Fini(void); -PyAPI_FUNC(void) PyCFunction_Fini(void); -PyAPI_FUNC(void) PyDict_Fini(void); -PyAPI_FUNC(void) PyTuple_Fini(void); -PyAPI_FUNC(void) PyList_Fini(void); -PyAPI_FUNC(void) PySet_Fini(void); -PyAPI_FUNC(void) PyBytes_Fini(void); -PyAPI_FUNC(void) PyByteArray_Fini(void); -PyAPI_FUNC(void) PyFloat_Fini(void); -PyAPI_FUNC(void) PyOS_FiniInterrupts(void); -PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); -PyAPI_FUNC(void) _PyGC_Fini(void); -PyAPI_FUNC(void) PySlice_Fini(void); -PyAPI_FUNC(void) _PyType_Fini(void); -PyAPI_FUNC(void) _PyRandom_Fini(void); - -PyAPI_DATA(PyThreadState *) _Py_Finalizing; -#endif - -/* Signals */ -typedef void (*PyOS_sighandler_t)(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); - -/* Random */ -PyAPI_FUNC(int) _PyOS_URandom (void *buffer, Py_ssize_t size); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYLIFECYCLE_H */ + +/* Interfaces to configure, query, create & destroy the Python runtime */ + +#ifndef Py_PYLIFECYCLE_H +#define Py_PYLIFECYCLE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); + +PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); + +#ifndef Py_LIMITED_API +/* Only used by applications that embed the interpreter and need to + * override the standard encoding determination mechanism + */ +PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, + const char *errors); +#endif + +PyAPI_FUNC(void) Py_Initialize(void); +PyAPI_FUNC(void) Py_InitializeEx(int); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int); +#endif +PyAPI_FUNC(void) Py_Finalize(void); +PyAPI_FUNC(int) Py_IsInitialized(void); +PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); +PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); + + +/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level + * exit functions. + */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void)); +#endif +PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); + +PyAPI_FUNC(void) Py_Exit(int); + +/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_RestoreSignals(void); + +PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); +#endif + +/* Bootstrap __main__ (defined in Modules/main.c) */ +PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); + +/* In getpath.c */ +PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); +PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); +PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); +PyAPI_FUNC(wchar_t *) Py_GetPath(void); +PyAPI_FUNC(void) Py_SetPath(const wchar_t *); +#ifdef MS_WINDOWS +int _Py_CheckPython3(); +#endif + +/* In their own files */ +PyAPI_FUNC(const char *) Py_GetVersion(void); +PyAPI_FUNC(const char *) Py_GetPlatform(void); +PyAPI_FUNC(const char *) Py_GetCopyright(void); +PyAPI_FUNC(const char *) Py_GetCompiler(void); +PyAPI_FUNC(const char *) Py_GetBuildInfo(void); +#ifndef Py_LIMITED_API +PyAPI_FUNC(const char *) _Py_hgidentifier(void); +PyAPI_FUNC(const char *) _Py_hgversion(void); +#endif + +/* Internal -- various one-time initializations */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); +PyAPI_FUNC(PyObject *) _PySys_Init(void); +PyAPI_FUNC(void) _PyImport_Init(void); +PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); +PyAPI_FUNC(void) _PyImportHooks_Init(void); +PyAPI_FUNC(int) _PyFrame_Init(void); +PyAPI_FUNC(int) _PyFloat_Init(void); +PyAPI_FUNC(int) PyByteArray_Init(void); +PyAPI_FUNC(void) _PyRandom_Init(void); +#endif + +/* Various internal finalizers */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyExc_Fini(void); +PyAPI_FUNC(void) _PyImport_Fini(void); +PyAPI_FUNC(void) PyMethod_Fini(void); +PyAPI_FUNC(void) PyFrame_Fini(void); +PyAPI_FUNC(void) PyCFunction_Fini(void); +PyAPI_FUNC(void) PyDict_Fini(void); +PyAPI_FUNC(void) PyTuple_Fini(void); +PyAPI_FUNC(void) PyList_Fini(void); +PyAPI_FUNC(void) PySet_Fini(void); +PyAPI_FUNC(void) PyBytes_Fini(void); +PyAPI_FUNC(void) PyByteArray_Fini(void); +PyAPI_FUNC(void) PyFloat_Fini(void); +PyAPI_FUNC(void) PyOS_FiniInterrupts(void); +PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); +PyAPI_FUNC(void) _PyGC_Fini(void); +PyAPI_FUNC(void) PySlice_Fini(void); +PyAPI_FUNC(void) _PyType_Fini(void); +PyAPI_FUNC(void) _PyRandom_Fini(void); + +PyAPI_DATA(PyThreadState *) _Py_Finalizing; +#endif + +/* Signals */ +typedef void (*PyOS_sighandler_t)(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); + +/* Random */ +PyAPI_FUNC(int) _PyOS_URandom (void *buffer, Py_ssize_t size); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYLIFECYCLE_H */ diff --git a/libs/nxpy/include/pymacconfig.h b/libs/nxpy/include/pymacconfig.h index 9dde11bd..a1eccea4 100644 --- a/libs/nxpy/include/pymacconfig.h +++ b/libs/nxpy/include/pymacconfig.h @@ -1,102 +1,102 @@ -#ifndef PYMACCONFIG_H -#define PYMACCONFIG_H - /* - * This file moves some of the autoconf magic to compile-time - * when building on MacOSX. This is needed for building 4-way - * universal binaries and for 64-bit universal binaries because - * the values redefined below aren't configure-time constant but - * only compile-time constant in these scenarios. - */ - -#if defined(__APPLE__) - -# undef SIZEOF_LONG -# undef SIZEOF_PTHREAD_T -# undef SIZEOF_SIZE_T -# undef SIZEOF_TIME_T -# undef SIZEOF_VOID_P -# undef SIZEOF__BOOL -# undef SIZEOF_UINTPTR_T -# undef SIZEOF_PTHREAD_T -# undef WORDS_BIGENDIAN -# undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 -# undef DOUBLE_IS_BIG_ENDIAN_IEEE754 -# undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 -# undef HAVE_GCC_ASM_FOR_X87 - -# undef VA_LIST_IS_ARRAY -# if defined(__LP64__) && defined(__x86_64__) -# define VA_LIST_IS_ARRAY 1 -# endif - -# undef HAVE_LARGEFILE_SUPPORT -# ifndef __LP64__ -# define HAVE_LARGEFILE_SUPPORT 1 -# endif - -# undef SIZEOF_LONG -# ifdef __LP64__ -# define SIZEOF__BOOL 1 -# define SIZEOF__BOOL 1 -# define SIZEOF_LONG 8 -# define SIZEOF_PTHREAD_T 8 -# define SIZEOF_SIZE_T 8 -# define SIZEOF_TIME_T 8 -# define SIZEOF_VOID_P 8 -# define SIZEOF_UINTPTR_T 8 -# define SIZEOF_PTHREAD_T 8 -# else -# ifdef __ppc__ -# define SIZEOF__BOOL 4 -# else -# define SIZEOF__BOOL 1 -# endif -# define SIZEOF_LONG 4 -# define SIZEOF_PTHREAD_T 4 -# define SIZEOF_SIZE_T 4 -# define SIZEOF_TIME_T 4 -# define SIZEOF_VOID_P 4 -# define SIZEOF_UINTPTR_T 4 -# define SIZEOF_PTHREAD_T 4 -# endif - -# if defined(__LP64__) - /* MacOSX 10.4 (the first release to support 64-bit code - * at all) only supports 64-bit in the UNIX layer. - * Therefore suppress the toolbox-glue in 64-bit mode. - */ - - /* In 64-bit mode setpgrp always has no arguments, in 32-bit - * mode that depends on the compilation environment - */ -# undef SETPGRP_HAVE_ARG - -# endif - -#ifdef __BIG_ENDIAN__ -#define WORDS_BIGENDIAN 1 -#define DOUBLE_IS_BIG_ENDIAN_IEEE754 -#else -#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 -#endif /* __BIG_ENDIAN */ - -#ifdef __i386__ -# define HAVE_GCC_ASM_FOR_X87 -#endif - - /* - * The definition in pyconfig.h is only valid on the OS release - * where configure ran on and not necessarily for all systems where - * the executable can be used on. - * - * Specifically: OSX 10.4 has limited supported for '%zd', while - * 10.5 has full support for '%zd'. A binary built on 10.5 won't - * work properly on 10.4 unless we suppress the definition - * of PY_FORMAT_SIZE_T - */ -#undef PY_FORMAT_SIZE_T - - -#endif /* defined(_APPLE__) */ - -#endif /* PYMACCONFIG_H */ +#ifndef PYMACCONFIG_H +#define PYMACCONFIG_H + /* + * This file moves some of the autoconf magic to compile-time + * when building on MacOSX. This is needed for building 4-way + * universal binaries and for 64-bit universal binaries because + * the values redefined below aren't configure-time constant but + * only compile-time constant in these scenarios. + */ + +#if defined(__APPLE__) + +# undef SIZEOF_LONG +# undef SIZEOF_PTHREAD_T +# undef SIZEOF_SIZE_T +# undef SIZEOF_TIME_T +# undef SIZEOF_VOID_P +# undef SIZEOF__BOOL +# undef SIZEOF_UINTPTR_T +# undef SIZEOF_PTHREAD_T +# undef WORDS_BIGENDIAN +# undef DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 +# undef DOUBLE_IS_BIG_ENDIAN_IEEE754 +# undef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 +# undef HAVE_GCC_ASM_FOR_X87 + +# undef VA_LIST_IS_ARRAY +# if defined(__LP64__) && defined(__x86_64__) +# define VA_LIST_IS_ARRAY 1 +# endif + +# undef HAVE_LARGEFILE_SUPPORT +# ifndef __LP64__ +# define HAVE_LARGEFILE_SUPPORT 1 +# endif + +# undef SIZEOF_LONG +# ifdef __LP64__ +# define SIZEOF__BOOL 1 +# define SIZEOF__BOOL 1 +# define SIZEOF_LONG 8 +# define SIZEOF_PTHREAD_T 8 +# define SIZEOF_SIZE_T 8 +# define SIZEOF_TIME_T 8 +# define SIZEOF_VOID_P 8 +# define SIZEOF_UINTPTR_T 8 +# define SIZEOF_PTHREAD_T 8 +# else +# ifdef __ppc__ +# define SIZEOF__BOOL 4 +# else +# define SIZEOF__BOOL 1 +# endif +# define SIZEOF_LONG 4 +# define SIZEOF_PTHREAD_T 4 +# define SIZEOF_SIZE_T 4 +# define SIZEOF_TIME_T 4 +# define SIZEOF_VOID_P 4 +# define SIZEOF_UINTPTR_T 4 +# define SIZEOF_PTHREAD_T 4 +# endif + +# if defined(__LP64__) + /* MacOSX 10.4 (the first release to support 64-bit code + * at all) only supports 64-bit in the UNIX layer. + * Therefore suppress the toolbox-glue in 64-bit mode. + */ + + /* In 64-bit mode setpgrp always has no arguments, in 32-bit + * mode that depends on the compilation environment + */ +# undef SETPGRP_HAVE_ARG + +# endif + +#ifdef __BIG_ENDIAN__ +#define WORDS_BIGENDIAN 1 +#define DOUBLE_IS_BIG_ENDIAN_IEEE754 +#else +#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 +#endif /* __BIG_ENDIAN */ + +#ifdef __i386__ +# define HAVE_GCC_ASM_FOR_X87 +#endif + + /* + * The definition in pyconfig.h is only valid on the OS release + * where configure ran on and not necessarily for all systems where + * the executable can be used on. + * + * Specifically: OSX 10.4 has limited supported for '%zd', while + * 10.5 has full support for '%zd'. A binary built on 10.5 won't + * work properly on 10.4 unless we suppress the definition + * of PY_FORMAT_SIZE_T + */ +#undef PY_FORMAT_SIZE_T + + +#endif /* defined(_APPLE__) */ + +#endif /* PYMACCONFIG_H */ diff --git a/libs/nxpy/include/pymacro.h b/libs/nxpy/include/pymacro.h index 3f6f5dce..b1c4605b 100644 --- a/libs/nxpy/include/pymacro.h +++ b/libs/nxpy/include/pymacro.h @@ -1,91 +1,91 @@ -#ifndef Py_PYMACRO_H -#define Py_PYMACRO_H - -/* Minimum value between x and y */ -#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) - -/* Maximum value between x and y */ -#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) - -/* Absolute value of the number x */ -#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) - -#define _Py_XSTRINGIFY(x) #x - -/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced - with "123" by the preprocessor. Defines are also replaced by their value. - For example Py_STRINGIFY(__LINE__) is replaced by the line number, not - by "__LINE__". */ -#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) - -/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ -#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) - -/* Assert a build-time dependency, as an expression. - - Your compile will fail if the condition isn't true, or can't be evaluated - by the compiler. This can be used in an expression: its value is 0. - - Example: - - #define foo_to_char(foo) \ - ((char *)(foo) \ - + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) - - Written by Rusty Russell, public domain, http://ccodearchive.net/ */ -#define Py_BUILD_ASSERT_EXPR(cond) \ - (sizeof(char [1 - 2*!(cond)]) - 1) - -/* Get the number of elements in a visible array - - This does not work on pointers, or arrays declared as [], or function - parameters. With correct compiler support, such usage will cause a build - error (see Py_BUILD_ASSERT_EXPR). - - Written by Rusty Russell, public domain, http://ccodearchive.net/ - - Requires at GCC 3.1+ */ -#if (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ - (((__GNUC__ == 3) && (__GNU_MINOR__ >= 1)) || (__GNUC__ >= 4))) -/* Two gcc extensions. - &a[0] degrades to a pointer: a different type from an array */ -#define Py_ARRAY_LENGTH(array) \ - (sizeof(array) / sizeof((array)[0]) \ - + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ - typeof(&(array)[0])))) -#else -#define Py_ARRAY_LENGTH(array) \ - (sizeof(array) / sizeof((array)[0])) -#endif - - -/* Define macros for inline documentation. */ -#define PyDoc_VAR(name) static char name[] -#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) -#ifdef WITH_DOC_STRINGS -#define PyDoc_STR(str) str -#else -#define PyDoc_STR(str) "" -#endif - -/* Below "a" is a power of 2. */ -/* Round down size "n" to be a multiple of "a". */ -#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) -/* Round up size "n" to be a multiple of "a". */ -#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ - (size_t)((a) - 1)) & ~(size_t)((a) - 1)) -/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ -#define _Py_ALIGN_DOWN(p, a) ((void *)((Py_uintptr_t)(p) & ~(Py_uintptr_t)((a) - 1))) -/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ -#define _Py_ALIGN_UP(p, a) ((void *)(((Py_uintptr_t)(p) + \ - (Py_uintptr_t)((a) - 1)) & ~(Py_uintptr_t)((a) - 1))) -/* Check if pointer "p" is aligned to "a"-bytes boundary. */ -#define _Py_IS_ALIGNED(p, a) (!((Py_uintptr_t)(p) & (Py_uintptr_t)((a) - 1))) - -#ifdef __GNUC__ -#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) -#else -#define Py_UNUSED(name) _unused_ ## name -#endif - -#endif /* Py_PYMACRO_H */ +#ifndef Py_PYMACRO_H +#define Py_PYMACRO_H + +/* Minimum value between x and y */ +#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +/* Maximum value between x and y */ +#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/* Absolute value of the number x */ +#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) + +#define _Py_XSTRINGIFY(x) #x + +/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced + with "123" by the preprocessor. Defines are also replaced by their value. + For example Py_STRINGIFY(__LINE__) is replaced by the line number, not + by "__LINE__". */ +#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) + +/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ +#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) + +/* Assert a build-time dependency, as an expression. + + Your compile will fail if the condition isn't true, or can't be evaluated + by the compiler. This can be used in an expression: its value is 0. + + Example: + + #define foo_to_char(foo) \ + ((char *)(foo) \ + + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) + + Written by Rusty Russell, public domain, http://ccodearchive.net/ */ +#define Py_BUILD_ASSERT_EXPR(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +/* Get the number of elements in a visible array + + This does not work on pointers, or arrays declared as [], or function + parameters. With correct compiler support, such usage will cause a build + error (see Py_BUILD_ASSERT_EXPR). + + Written by Rusty Russell, public domain, http://ccodearchive.net/ + + Requires at GCC 3.1+ */ +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ + (((__GNUC__ == 3) && (__GNU_MINOR__ >= 1)) || (__GNUC__ >= 4))) +/* Two gcc extensions. + &a[0] degrades to a pointer: a different type from an array */ +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0]) \ + + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ + typeof(&(array)[0])))) +#else +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif + + +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif + +/* Below "a" is a power of 2. */ +/* Round down size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) +/* Round up size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ + (size_t)((a) - 1)) & ~(size_t)((a) - 1)) +/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ +#define _Py_ALIGN_DOWN(p, a) ((void *)((Py_uintptr_t)(p) & ~(Py_uintptr_t)((a) - 1))) +/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ +#define _Py_ALIGN_UP(p, a) ((void *)(((Py_uintptr_t)(p) + \ + (Py_uintptr_t)((a) - 1)) & ~(Py_uintptr_t)((a) - 1))) +/* Check if pointer "p" is aligned to "a"-bytes boundary. */ +#define _Py_IS_ALIGNED(p, a) (!((Py_uintptr_t)(p) & (Py_uintptr_t)((a) - 1))) + +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif + +#endif /* Py_PYMACRO_H */ diff --git a/libs/nxpy/include/pymath.h b/libs/nxpy/include/pymath.h index 1c8d718f..51d60068 100644 --- a/libs/nxpy/include/pymath.h +++ b/libs/nxpy/include/pymath.h @@ -1,212 +1,212 @@ -#ifndef Py_PYMATH_H -#define Py_PYMATH_H - -#include "pyconfig.h" /* include for defines */ - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to mathematical -functions and constants -**************************************************************************/ - -/* Python provides implementations for copysign, round and hypot in - * Python/pymath.c just in case your math library doesn't provide the - * functions. - * - *Note: PC/pyconfig.h defines copysign as _copysign - */ -#ifndef HAVE_COPYSIGN -extern double copysign(double, double); -#endif - -#ifndef HAVE_ROUND -extern double round(double); -#endif - -#ifndef HAVE_HYPOT -extern double hypot(double, double); -#endif - -/* extra declarations */ -#ifndef _MSC_VER -#ifndef __STDC__ -extern double fmod (double, double); -extern double frexp (double, int *); -extern double ldexp (double, int); -extern double modf (double, double *); -extern double pow(double, double); -#endif /* __STDC__ */ -#endif /* _MSC_VER */ - -/* High precision definition of pi and e (Euler) - * The values are taken from libc6's math.h. - */ -#ifndef Py_MATH_PIl -#define Py_MATH_PIl 3.1415926535897932384626433832795029L -#endif -#ifndef Py_MATH_PI -#define Py_MATH_PI 3.14159265358979323846 -#endif - -#ifndef Py_MATH_El -#define Py_MATH_El 2.7182818284590452353602874713526625L -#endif - -#ifndef Py_MATH_E -#define Py_MATH_E 2.7182818284590452354 -#endif - -/* On x86, Py_FORCE_DOUBLE forces a floating-point number out of an x87 FPU - register and into a 64-bit memory location, rounding from extended - precision to double precision in the process. On other platforms it does - nothing. */ - -/* we take double rounding as evidence of x87 usage */ -#ifndef Py_LIMITED_API -#ifndef Py_FORCE_DOUBLE -# ifdef X87_DOUBLE_ROUNDING -PyAPI_FUNC(double) _Py_force_double(double); -# define Py_FORCE_DOUBLE(X) (_Py_force_double(X)) -# else -# define Py_FORCE_DOUBLE(X) (X) -# endif -#endif -#endif - -#ifndef Py_LIMITED_API -#ifdef HAVE_GCC_ASM_FOR_X87 -PyAPI_FUNC(unsigned short) _Py_get_387controlword(void); -PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); -#endif -#endif - -/* Py_IS_NAN(X) - * Return 1 if float or double arg is a NaN, else 0. - * Caution: - * X is evaluated more than once. - * This may not work on all platforms. Each platform has *some* - * way to spell this, though -- override in pyconfig.h if you have - * a platform where it doesn't work. - * Note: PC/pyconfig.h defines Py_IS_NAN as _isnan - */ -#ifndef Py_IS_NAN -#if defined HAVE_DECL_ISNAN && HAVE_DECL_ISNAN == 1 -#define Py_IS_NAN(X) isnan(X) -#else -#define Py_IS_NAN(X) ((X) != (X)) -#endif -#endif - -/* Py_IS_INFINITY(X) - * Return 1 if float or double arg is an infinity, else 0. - * Caution: - * X is evaluated more than once. - * This implementation may set the underflow flag if |X| is very small; - * it really can't be implemented correctly (& easily) before C99. - * Override in pyconfig.h if you have a better spelling on your platform. - * Py_FORCE_DOUBLE is used to avoid getting false negatives from a - * non-infinite value v sitting in an 80-bit x87 register such that - * v becomes infinite when spilled from the register to 64-bit memory. - * Note: PC/pyconfig.h defines Py_IS_INFINITY as _isinf - */ -#ifndef Py_IS_INFINITY -# if defined HAVE_DECL_ISINF && HAVE_DECL_ISINF == 1 -# define Py_IS_INFINITY(X) isinf(X) -# else -# define Py_IS_INFINITY(X) ((X) && \ - (Py_FORCE_DOUBLE(X)*0.5 == Py_FORCE_DOUBLE(X))) -# endif -#endif - -/* Py_IS_FINITE(X) - * Return 1 if float or double arg is neither infinite nor NAN, else 0. - * Some compilers (e.g. VisualStudio) have intrisics for this, so a special - * macro for this particular test is useful - * Note: PC/pyconfig.h defines Py_IS_FINITE as _finite - */ -#ifndef Py_IS_FINITE -#if defined HAVE_DECL_ISFINITE && HAVE_DECL_ISFINITE == 1 -#define Py_IS_FINITE(X) isfinite(X) -#elif defined HAVE_FINITE -#define Py_IS_FINITE(X) finite(X) -#else -#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X)) -#endif -#endif - -/* HUGE_VAL is supposed to expand to a positive double infinity. Python - * uses Py_HUGE_VAL instead because some platforms are broken in this - * respect. We used to embed code in pyport.h to try to worm around that, - * but different platforms are broken in conflicting ways. If you're on - * a platform where HUGE_VAL is defined incorrectly, fiddle your Python - * config to #define Py_HUGE_VAL to something that works on your platform. - */ -#ifndef Py_HUGE_VAL -#define Py_HUGE_VAL HUGE_VAL -#endif - -/* Py_NAN - * A value that evaluates to a NaN. On IEEE 754 platforms INF*0 or - * INF/INF works. Define Py_NO_NAN in pyconfig.h if your platform - * doesn't support NaNs. - */ -#if !defined(Py_NAN) && !defined(Py_NO_NAN) -#if !defined(__INTEL_COMPILER) - #define Py_NAN (Py_HUGE_VAL * 0.) -#else /* __INTEL_COMPILER */ - #if defined(ICC_NAN_STRICT) - #pragma float_control(push) - #pragma float_control(precise, on) - #pragma float_control(except, on) - #if defined(_MSC_VER) - __declspec(noinline) - #else /* Linux */ - __attribute__((noinline)) - #endif /* _MSC_VER */ - static double __icc_nan() - { - return sqrt(-1.0); - } - #pragma float_control (pop) - #define Py_NAN __icc_nan() - #else /* ICC_NAN_RELAXED as default for Intel Compiler */ - static union { unsigned char buf[8]; double __icc_nan; } __nan_store = {0,0,0,0,0,0,0xf8,0x7f}; - #define Py_NAN (__nan_store.__icc_nan) - #endif /* ICC_NAN_STRICT */ -#endif /* __INTEL_COMPILER */ -#endif - -/* Py_OVERFLOWED(X) - * Return 1 iff a libm function overflowed. Set errno to 0 before calling - * a libm function, and invoke this macro after, passing the function - * result. - * Caution: - * This isn't reliable. C99 no longer requires libm to set errno under - * any exceptional condition, but does require +- HUGE_VAL return - * values on overflow. A 754 box *probably* maps HUGE_VAL to a - * double infinity, and we're cool if that's so, unless the input - * was an infinity and an infinity is the expected result. A C89 - * system sets errno to ERANGE, so we check for that too. We're - * out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or - * if the returned result is a NaN, or if a C89 box returns HUGE_VAL - * in non-overflow cases. - * X is evaluated more than once. - * Some platforms have better way to spell this, so expect some #ifdef'ery. - * - * OpenBSD uses 'isinf()' because a compiler bug on that platform causes - * the longer macro version to be mis-compiled. This isn't optimal, and - * should be removed once a newer compiler is available on that platform. - * The system that had the failure was running OpenBSD 3.2 on Intel, with - * gcc 2.95.3. - * - * According to Tim's checkin, the FreeBSD systems use isinf() to work - * around a FPE bug on that platform. - */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#define Py_OVERFLOWED(X) isinf(X) -#else -#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ - (X) == Py_HUGE_VAL || \ - (X) == -Py_HUGE_VAL)) -#endif - -#endif /* Py_PYMATH_H */ +#ifndef Py_PYMATH_H +#define Py_PYMATH_H + +#include "pyconfig.h" /* include for defines */ + +/************************************************************************** +Symbols and macros to supply platform-independent interfaces to mathematical +functions and constants +**************************************************************************/ + +/* Python provides implementations for copysign, round and hypot in + * Python/pymath.c just in case your math library doesn't provide the + * functions. + * + *Note: PC/pyconfig.h defines copysign as _copysign + */ +#ifndef HAVE_COPYSIGN +extern double copysign(double, double); +#endif + +#ifndef HAVE_ROUND +extern double round(double); +#endif + +#ifndef HAVE_HYPOT +extern double hypot(double, double); +#endif + +/* extra declarations */ +#ifndef _MSC_VER +#ifndef __STDC__ +extern double fmod (double, double); +extern double frexp (double, int *); +extern double ldexp (double, int); +extern double modf (double, double *); +extern double pow(double, double); +#endif /* __STDC__ */ +#endif /* _MSC_VER */ + +/* High precision definition of pi and e (Euler) + * The values are taken from libc6's math.h. + */ +#ifndef Py_MATH_PIl +#define Py_MATH_PIl 3.1415926535897932384626433832795029L +#endif +#ifndef Py_MATH_PI +#define Py_MATH_PI 3.14159265358979323846 +#endif + +#ifndef Py_MATH_El +#define Py_MATH_El 2.7182818284590452353602874713526625L +#endif + +#ifndef Py_MATH_E +#define Py_MATH_E 2.7182818284590452354 +#endif + +/* On x86, Py_FORCE_DOUBLE forces a floating-point number out of an x87 FPU + register and into a 64-bit memory location, rounding from extended + precision to double precision in the process. On other platforms it does + nothing. */ + +/* we take double rounding as evidence of x87 usage */ +#ifndef Py_LIMITED_API +#ifndef Py_FORCE_DOUBLE +# ifdef X87_DOUBLE_ROUNDING +PyAPI_FUNC(double) _Py_force_double(double); +# define Py_FORCE_DOUBLE(X) (_Py_force_double(X)) +# else +# define Py_FORCE_DOUBLE(X) (X) +# endif +#endif +#endif + +#ifndef Py_LIMITED_API +#ifdef HAVE_GCC_ASM_FOR_X87 +PyAPI_FUNC(unsigned short) _Py_get_387controlword(void); +PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); +#endif +#endif + +/* Py_IS_NAN(X) + * Return 1 if float or double arg is a NaN, else 0. + * Caution: + * X is evaluated more than once. + * This may not work on all platforms. Each platform has *some* + * way to spell this, though -- override in pyconfig.h if you have + * a platform where it doesn't work. + * Note: PC/pyconfig.h defines Py_IS_NAN as _isnan + */ +#ifndef Py_IS_NAN +#if defined HAVE_DECL_ISNAN && HAVE_DECL_ISNAN == 1 +#define Py_IS_NAN(X) isnan(X) +#else +#define Py_IS_NAN(X) ((X) != (X)) +#endif +#endif + +/* Py_IS_INFINITY(X) + * Return 1 if float or double arg is an infinity, else 0. + * Caution: + * X is evaluated more than once. + * This implementation may set the underflow flag if |X| is very small; + * it really can't be implemented correctly (& easily) before C99. + * Override in pyconfig.h if you have a better spelling on your platform. + * Py_FORCE_DOUBLE is used to avoid getting false negatives from a + * non-infinite value v sitting in an 80-bit x87 register such that + * v becomes infinite when spilled from the register to 64-bit memory. + * Note: PC/pyconfig.h defines Py_IS_INFINITY as _isinf + */ +#ifndef Py_IS_INFINITY +# if defined HAVE_DECL_ISINF && HAVE_DECL_ISINF == 1 +# define Py_IS_INFINITY(X) isinf(X) +# else +# define Py_IS_INFINITY(X) ((X) && \ + (Py_FORCE_DOUBLE(X)*0.5 == Py_FORCE_DOUBLE(X))) +# endif +#endif + +/* Py_IS_FINITE(X) + * Return 1 if float or double arg is neither infinite nor NAN, else 0. + * Some compilers (e.g. VisualStudio) have intrisics for this, so a special + * macro for this particular test is useful + * Note: PC/pyconfig.h defines Py_IS_FINITE as _finite + */ +#ifndef Py_IS_FINITE +#if defined HAVE_DECL_ISFINITE && HAVE_DECL_ISFINITE == 1 +#define Py_IS_FINITE(X) isfinite(X) +#elif defined HAVE_FINITE +#define Py_IS_FINITE(X) finite(X) +#else +#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X)) +#endif +#endif + +/* HUGE_VAL is supposed to expand to a positive double infinity. Python + * uses Py_HUGE_VAL instead because some platforms are broken in this + * respect. We used to embed code in pyport.h to try to worm around that, + * but different platforms are broken in conflicting ways. If you're on + * a platform where HUGE_VAL is defined incorrectly, fiddle your Python + * config to #define Py_HUGE_VAL to something that works on your platform. + */ +#ifndef Py_HUGE_VAL +#define Py_HUGE_VAL HUGE_VAL +#endif + +/* Py_NAN + * A value that evaluates to a NaN. On IEEE 754 platforms INF*0 or + * INF/INF works. Define Py_NO_NAN in pyconfig.h if your platform + * doesn't support NaNs. + */ +#if !defined(Py_NAN) && !defined(Py_NO_NAN) +#if !defined(__INTEL_COMPILER) + #define Py_NAN (Py_HUGE_VAL * 0.) +#else /* __INTEL_COMPILER */ + #if defined(ICC_NAN_STRICT) + #pragma float_control(push) + #pragma float_control(precise, on) + #pragma float_control(except, on) + #if defined(_MSC_VER) + __declspec(noinline) + #else /* Linux */ + __attribute__((noinline)) + #endif /* _MSC_VER */ + static double __icc_nan() + { + return sqrt(-1.0); + } + #pragma float_control (pop) + #define Py_NAN __icc_nan() + #else /* ICC_NAN_RELAXED as default for Intel Compiler */ + static union { unsigned char buf[8]; double __icc_nan; } __nan_store = {0,0,0,0,0,0,0xf8,0x7f}; + #define Py_NAN (__nan_store.__icc_nan) + #endif /* ICC_NAN_STRICT */ +#endif /* __INTEL_COMPILER */ +#endif + +/* Py_OVERFLOWED(X) + * Return 1 iff a libm function overflowed. Set errno to 0 before calling + * a libm function, and invoke this macro after, passing the function + * result. + * Caution: + * This isn't reliable. C99 no longer requires libm to set errno under + * any exceptional condition, but does require +- HUGE_VAL return + * values on overflow. A 754 box *probably* maps HUGE_VAL to a + * double infinity, and we're cool if that's so, unless the input + * was an infinity and an infinity is the expected result. A C89 + * system sets errno to ERANGE, so we check for that too. We're + * out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or + * if the returned result is a NaN, or if a C89 box returns HUGE_VAL + * in non-overflow cases. + * X is evaluated more than once. + * Some platforms have better way to spell this, so expect some #ifdef'ery. + * + * OpenBSD uses 'isinf()' because a compiler bug on that platform causes + * the longer macro version to be mis-compiled. This isn't optimal, and + * should be removed once a newer compiler is available on that platform. + * The system that had the failure was running OpenBSD 3.2 on Intel, with + * gcc 2.95.3. + * + * According to Tim's checkin, the FreeBSD systems use isinf() to work + * around a FPE bug on that platform. + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#define Py_OVERFLOWED(X) isinf(X) +#else +#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ + (X) == Py_HUGE_VAL || \ + (X) == -Py_HUGE_VAL)) +#endif + +#endif /* Py_PYMATH_H */ diff --git a/libs/nxpy/include/pymem.h b/libs/nxpy/include/pymem.h index 043db64d..8fd34ef5 100644 --- a/libs/nxpy/include/pymem.h +++ b/libs/nxpy/include/pymem.h @@ -1,188 +1,188 @@ -/* The PyMem_ family: low-level memory allocation interfaces. - See objimpl.h for the PyObject_ memory family. -*/ - -#ifndef Py_PYMEM_H -#define Py_PYMEM_H - -#include "pyport.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); -PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize); -PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyMem_RawFree(void *ptr); -#endif - - -/* BEWARE: - - Each interface exports both functions and macros. Extension modules should - use the functions, to ensure binary compatibility across Python versions. - Because the Python implementation is free to change internal details, and - the macros may (or may not) expose details for speed, if you do use the - macros you must recompile your extensions with each Python release. - - Never mix calls to PyMem_ with calls to the platform malloc/realloc/ - calloc/free. For example, on Windows different DLLs may end up using - different heaps, and if you use PyMem_Malloc you'll get the memory from the - heap used by the Python DLL; it could be a disaster if you free()'ed that - directly in your own extension. Using PyMem_Free instead ensures Python - can return the memory to the proper heap. As another example, in - PYMALLOC_DEBUG mode, Python wraps all calls to all PyMem_ and PyObject_ - memory functions in special debugging wrappers that add additional - debugging info to dynamic memory blocks. The system routines have no idea - what to do with that stuff, and the Python wrappers have no idea what to do - with raw blocks obtained directly by the system routines then. - - The GIL must be held when using these APIs. -*/ - -/* - * Raw memory interface - * ==================== - */ - -/* Functions - - Functions supplying platform-independent semantics for malloc/realloc/ - free. These functions make sure that allocating 0 bytes returns a distinct - non-NULL pointer (whenever possible -- if we're flat out of memory, NULL - may be returned), even if the platform malloc and realloc don't. - Returned pointers must be checked for NULL explicitly. No action is - performed on failure (no exception is set, no warning is printed, etc). -*/ - -PyAPI_FUNC(void *) PyMem_Malloc(size_t size); -PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); -PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); -PyAPI_FUNC(void) PyMem_Free(void *ptr); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) _PyMem_RawStrdup(const char *str); -PyAPI_FUNC(char *) _PyMem_Strdup(const char *str); -#endif - -/* Macros. */ - -/* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL - for malloc(0), which would be treated as an error. Some platforms - would return a pointer with no memory behind it, which would break - pymalloc. To solve these problems, allocate an extra byte. */ -/* Returns NULL to indicate error if a negative size or size larger than - Py_ssize_t can represent is supplied. Helps prevents security holes. */ -#define PyMem_MALLOC(n) PyMem_Malloc(n) -#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n) -#define PyMem_FREE(p) PyMem_Free(p) - -/* - * Type-oriented memory interface - * ============================== - * - * Allocate memory for n objects of the given type. Returns a new pointer - * or NULL if the request was too large or memory allocation failed. Use - * these macros rather than doing the multiplication yourself so that proper - * overflow checking is always done. - */ - -#define PyMem_New(type, n) \ - ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - ( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) -#define PyMem_NEW(type, n) \ - ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) ) - -/* - * The value of (p) is always clobbered by this macro regardless of success. - * The caller MUST check if (p) is NULL afterwards and deal with the memory - * error if so. This means the original value of (p) MUST be saved for the - * caller's memory error handler to not lose track of it. - */ -#define PyMem_Resize(p, type, n) \ - ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) -#define PyMem_RESIZE(p, type, n) \ - ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ - (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) - -/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used - * anymore. They're just confusing aliases for PyMem_{Free,FREE} now. - */ -#define PyMem_Del PyMem_Free -#define PyMem_DEL PyMem_FREE - -#ifndef Py_LIMITED_API -typedef enum { - /* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */ - PYMEM_DOMAIN_RAW, - - /* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */ - PYMEM_DOMAIN_MEM, - - /* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */ - PYMEM_DOMAIN_OBJ -} PyMemAllocatorDomain; - -typedef struct { - /* user context passed as the first argument to the 4 functions */ - void *ctx; - - /* allocate a memory block */ - void* (*malloc) (void *ctx, size_t size); - - /* allocate a memory block initialized by zeros */ - void* (*calloc) (void *ctx, size_t nelem, size_t elsize); - - /* allocate or resize a memory block */ - void* (*realloc) (void *ctx, void *ptr, size_t new_size); - - /* release a memory block */ - void (*free) (void *ctx, void *ptr); -} PyMemAllocatorEx; - -/* Get the memory block allocator of the specified domain. */ -PyAPI_FUNC(void) PyMem_GetAllocator(PyMemAllocatorDomain domain, - PyMemAllocatorEx *allocator); - -/* Set the memory block allocator of the specified domain. - - The new allocator must return a distinct non-NULL pointer when requesting - zero bytes. - - For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL - is not held when the allocator is called. - - If the new allocator is not a hook (don't call the previous allocator), the - PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks - on top on the new allocator. */ -PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain, - PyMemAllocatorEx *allocator); - -/* Setup hooks to detect bugs in the following Python memory allocator - functions: - - - PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() - - PyMem_Malloc(), PyMem_Realloc(), PyMem_Free() - - PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() - - Newly allocated memory is filled with the byte 0xCB, freed memory is filled - with the byte 0xDB. Additionnal checks: - - - detect API violations, ex: PyObject_Free() called on a buffer allocated - by PyMem_Malloc() - - detect write before the start of the buffer (buffer underflow) - - detect write after the end of the buffer (buffer overflow) - - The function does nothing if Python is not compiled is debug mode. */ -PyAPI_FUNC(void) PyMem_SetupDebugHooks(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYMEM_H */ +/* The PyMem_ family: low-level memory allocation interfaces. + See objimpl.h for the PyObject_ memory family. +*/ + +#ifndef Py_PYMEM_H +#define Py_PYMEM_H + +#include "pyport.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); +PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize); +PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_RawFree(void *ptr); +#endif + + +/* BEWARE: + + Each interface exports both functions and macros. Extension modules should + use the functions, to ensure binary compatibility across Python versions. + Because the Python implementation is free to change internal details, and + the macros may (or may not) expose details for speed, if you do use the + macros you must recompile your extensions with each Python release. + + Never mix calls to PyMem_ with calls to the platform malloc/realloc/ + calloc/free. For example, on Windows different DLLs may end up using + different heaps, and if you use PyMem_Malloc you'll get the memory from the + heap used by the Python DLL; it could be a disaster if you free()'ed that + directly in your own extension. Using PyMem_Free instead ensures Python + can return the memory to the proper heap. As another example, in + PYMALLOC_DEBUG mode, Python wraps all calls to all PyMem_ and PyObject_ + memory functions in special debugging wrappers that add additional + debugging info to dynamic memory blocks. The system routines have no idea + what to do with that stuff, and the Python wrappers have no idea what to do + with raw blocks obtained directly by the system routines then. + + The GIL must be held when using these APIs. +*/ + +/* + * Raw memory interface + * ==================== + */ + +/* Functions + + Functions supplying platform-independent semantics for malloc/realloc/ + free. These functions make sure that allocating 0 bytes returns a distinct + non-NULL pointer (whenever possible -- if we're flat out of memory, NULL + may be returned), even if the platform malloc and realloc don't. + Returned pointers must be checked for NULL explicitly. No action is + performed on failure (no exception is set, no warning is printed, etc). +*/ + +PyAPI_FUNC(void *) PyMem_Malloc(size_t size); +PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); +PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); +PyAPI_FUNC(void) PyMem_Free(void *ptr); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(char *) _PyMem_RawStrdup(const char *str); +PyAPI_FUNC(char *) _PyMem_Strdup(const char *str); +#endif + +/* Macros. */ + +/* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL + for malloc(0), which would be treated as an error. Some platforms + would return a pointer with no memory behind it, which would break + pymalloc. To solve these problems, allocate an extra byte. */ +/* Returns NULL to indicate error if a negative size or size larger than + Py_ssize_t can represent is supplied. Helps prevents security holes. */ +#define PyMem_MALLOC(n) PyMem_Malloc(n) +#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n) +#define PyMem_FREE(p) PyMem_Free(p) + +/* + * Type-oriented memory interface + * ============================== + * + * Allocate memory for n objects of the given type. Returns a new pointer + * or NULL if the request was too large or memory allocation failed. Use + * these macros rather than doing the multiplication yourself so that proper + * overflow checking is always done. + */ + +#define PyMem_New(type, n) \ + ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ + ( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) +#define PyMem_NEW(type, n) \ + ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ + ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) ) + +/* + * The value of (p) is always clobbered by this macro regardless of success. + * The caller MUST check if (p) is NULL afterwards and deal with the memory + * error if so. This means the original value of (p) MUST be saved for the + * caller's memory error handler to not lose track of it. + */ +#define PyMem_Resize(p, type, n) \ + ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ + (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) +#define PyMem_RESIZE(p, type, n) \ + ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL : \ + (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) + +/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used + * anymore. They're just confusing aliases for PyMem_{Free,FREE} now. + */ +#define PyMem_Del PyMem_Free +#define PyMem_DEL PyMem_FREE + +#ifndef Py_LIMITED_API +typedef enum { + /* PyMem_RawMalloc(), PyMem_RawRealloc() and PyMem_RawFree() */ + PYMEM_DOMAIN_RAW, + + /* PyMem_Malloc(), PyMem_Realloc() and PyMem_Free() */ + PYMEM_DOMAIN_MEM, + + /* PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() */ + PYMEM_DOMAIN_OBJ +} PyMemAllocatorDomain; + +typedef struct { + /* user context passed as the first argument to the 4 functions */ + void *ctx; + + /* allocate a memory block */ + void* (*malloc) (void *ctx, size_t size); + + /* allocate a memory block initialized by zeros */ + void* (*calloc) (void *ctx, size_t nelem, size_t elsize); + + /* allocate or resize a memory block */ + void* (*realloc) (void *ctx, void *ptr, size_t new_size); + + /* release a memory block */ + void (*free) (void *ctx, void *ptr); +} PyMemAllocatorEx; + +/* Get the memory block allocator of the specified domain. */ +PyAPI_FUNC(void) PyMem_GetAllocator(PyMemAllocatorDomain domain, + PyMemAllocatorEx *allocator); + +/* Set the memory block allocator of the specified domain. + + The new allocator must return a distinct non-NULL pointer when requesting + zero bytes. + + For the PYMEM_DOMAIN_RAW domain, the allocator must be thread-safe: the GIL + is not held when the allocator is called. + + If the new allocator is not a hook (don't call the previous allocator), the + PyMem_SetupDebugHooks() function must be called to reinstall the debug hooks + on top on the new allocator. */ +PyAPI_FUNC(void) PyMem_SetAllocator(PyMemAllocatorDomain domain, + PyMemAllocatorEx *allocator); + +/* Setup hooks to detect bugs in the following Python memory allocator + functions: + + - PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() + - PyMem_Malloc(), PyMem_Realloc(), PyMem_Free() + - PyObject_Malloc(), PyObject_Realloc() and PyObject_Free() + + Newly allocated memory is filled with the byte 0xCB, freed memory is filled + with the byte 0xDB. Additionnal checks: + + - detect API violations, ex: PyObject_Free() called on a buffer allocated + by PyMem_Malloc() + - detect write before the start of the buffer (buffer underflow) + - detect write after the end of the buffer (buffer overflow) + + The function does nothing if Python is not compiled is debug mode. */ +PyAPI_FUNC(void) PyMem_SetupDebugHooks(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYMEM_H */ diff --git a/libs/nxpy/include/pyport.h b/libs/nxpy/include/pyport.h index e7e51784..de7c4dfc 100644 --- a/libs/nxpy/include/pyport.h +++ b/libs/nxpy/include/pyport.h @@ -1,909 +1,909 @@ -#ifndef Py_PYPORT_H -#define Py_PYPORT_H - -#include "pyconfig.h" /* include for defines */ - -/* Some versions of HP-UX & Solaris need inttypes.h for int32_t, - INT32_MAX, etc. */ -#ifdef HAVE_INTTYPES_H -#include -#endif - -#ifdef HAVE_STDINT_H -#include -#endif - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to basic -C language & library operations whose spellings vary across platforms. - -Please try to make documentation here as clear as possible: by definition, -the stuff here is trying to illuminate C's darkest corners. - -Config #defines referenced here: - -SIGNED_RIGHT_SHIFT_ZERO_FILLS -Meaning: To be defined iff i>>j does not extend the sign bit when i is a - signed integral type and i < 0. -Used in: Py_ARITHMETIC_RIGHT_SHIFT - -Py_DEBUG -Meaning: Extra checks compiled in for debug mode. -Used in: Py_SAFE_DOWNCAST - -HAVE_UINTPTR_T -Meaning: The C9X type uintptr_t is supported by the compiler -Used in: Py_uintptr_t - -HAVE_LONG_LONG -Meaning: The compiler supports the C type "long long" -Used in: PY_LONG_LONG - -**************************************************************************/ - -/* typedefs for some C9X-defined synonyms for integral types. - * - * The names in Python are exactly the same as the C9X names, except with a - * Py_ prefix. Until C9X is universally implemented, this is the only way - * to ensure that Python gets reliable names that don't conflict with names - * in non-Python code that are playing their own tricks to define the C9X - * names. - * - * NOTE: don't go nuts here! Python has no use for *most* of the C9X - * integral synonyms. Only define the ones we actually need. - */ - -#ifdef HAVE_LONG_LONG -#ifndef PY_LONG_LONG -#define PY_LONG_LONG long long -#if defined(LLONG_MAX) -/* If LLONG_MAX is defined in limits.h, use that. */ -#define PY_LLONG_MIN LLONG_MIN -#define PY_LLONG_MAX LLONG_MAX -#define PY_ULLONG_MAX ULLONG_MAX -#elif defined(__LONG_LONG_MAX__) -/* Otherwise, if GCC has a builtin define, use that. (Definition of - * PY_LLONG_MIN assumes two's complement with no trap representation.) */ -#define PY_LLONG_MAX __LONG_LONG_MAX__ -#define PY_LLONG_MIN (-PY_LLONG_MAX - 1) -#define PY_ULLONG_MAX (PY_LLONG_MAX * Py_ULL(2) + 1) -#elif defined(SIZEOF_LONG_LONG) -/* Otherwise compute from SIZEOF_LONG_LONG, assuming two's complement, no - padding bits, and no trap representation. Note: PY_ULLONG_MAX was - previously #defined as (~0ULL) here; but that'll give the wrong value in a - preprocessor expression on systems where long long != intmax_t. */ -#define PY_LLONG_MAX \ - (1 + 2 * ((Py_LL(1) << (CHAR_BIT * SIZEOF_LONG_LONG - 2)) - 1)) -#define PY_LLONG_MIN (-PY_LLONG_MAX - 1) -#define PY_ULLONG_MAX (PY_LLONG_MAX * Py_ULL(2) + 1) -#endif /* LLONG_MAX */ -#endif -#endif /* HAVE_LONG_LONG */ - -/* a build with 30-bit digits for Python integers needs an exact-width - * 32-bit unsigned integer type to store those digits. (We could just use - * type 'unsigned long', but that would be wasteful on a system where longs - * are 64-bits.) On Unix systems, the autoconf macro AC_TYPE_UINT32_T defines - * uint32_t to be such a type unless stdint.h or inttypes.h defines uint32_t. - * However, it doesn't set HAVE_UINT32_T, so we do that here. - */ -#ifdef uint32_t -#define HAVE_UINT32_T 1 -#endif - -#ifdef HAVE_UINT32_T -#ifndef PY_UINT32_T -#define PY_UINT32_T uint32_t -#endif -#endif - -/* Macros for a 64-bit unsigned integer type; used for type 'twodigits' in the - * integer implementation, when 30-bit digits are enabled. - */ -#ifdef uint64_t -#define HAVE_UINT64_T 1 -#endif - -#ifdef HAVE_UINT64_T -#ifndef PY_UINT64_T -#define PY_UINT64_T uint64_t -#endif -#endif - -/* Signed variants of the above */ -#ifdef int32_t -#define HAVE_INT32_T 1 -#endif - -#ifdef HAVE_INT32_T -#ifndef PY_INT32_T -#define PY_INT32_T int32_t -#endif -#endif - -#ifdef int64_t -#define HAVE_INT64_T 1 -#endif - -#ifdef HAVE_INT64_T -#ifndef PY_INT64_T -#define PY_INT64_T int64_t -#endif -#endif - -/* If PYLONG_BITS_IN_DIGIT is not defined then we'll use 30-bit digits if all - the necessary integer types are available, and we're on a 64-bit platform - (as determined by SIZEOF_VOID_P); otherwise we use 15-bit digits. */ - -#ifndef PYLONG_BITS_IN_DIGIT -#if (defined HAVE_UINT64_T && defined HAVE_INT64_T && \ - defined HAVE_UINT32_T && defined HAVE_INT32_T && SIZEOF_VOID_P >= 8) -#define PYLONG_BITS_IN_DIGIT 30 -#else -#define PYLONG_BITS_IN_DIGIT 15 -#endif -#endif - -/* uintptr_t is the C9X name for an unsigned integral type such that a - * legitimate void* can be cast to uintptr_t and then back to void* again - * without loss of information. Similarly for intptr_t, wrt a signed - * integral type. - */ -#ifdef HAVE_UINTPTR_T -typedef uintptr_t Py_uintptr_t; -typedef intptr_t Py_intptr_t; - -#elif SIZEOF_VOID_P <= SIZEOF_INT -typedef unsigned int Py_uintptr_t; -typedef int Py_intptr_t; - -#elif SIZEOF_VOID_P <= SIZEOF_LONG -typedef unsigned long Py_uintptr_t; -typedef long Py_intptr_t; - -#elif defined(HAVE_LONG_LONG) && (SIZEOF_VOID_P <= SIZEOF_LONG_LONG) -typedef unsigned PY_LONG_LONG Py_uintptr_t; -typedef PY_LONG_LONG Py_intptr_t; - -#else -# error "Python needs a typedef for Py_uintptr_t in pyport.h." -#endif /* HAVE_UINTPTR_T */ - -/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == - * sizeof(size_t). C99 doesn't define such a thing directly (size_t is an - * unsigned integral type). See PEP 353 for details. - */ -#ifdef HAVE_SSIZE_T -typedef ssize_t Py_ssize_t; -#elif SIZEOF_VOID_P == SIZEOF_SIZE_T -typedef Py_intptr_t Py_ssize_t; -#else -# error "Python needs a typedef for Py_ssize_t in pyport.h." -#endif - -/* Py_hash_t is the same size as a pointer. */ -#define SIZEOF_PY_HASH_T SIZEOF_SIZE_T -typedef Py_ssize_t Py_hash_t; -/* Py_uhash_t is the unsigned equivalent needed to calculate numeric hash. */ -#define SIZEOF_PY_UHASH_T SIZEOF_SIZE_T -typedef size_t Py_uhash_t; - -/* Only used for compatibility with code that may not be PY_SSIZE_T_CLEAN. */ -#ifdef PY_SSIZE_T_CLEAN -typedef Py_ssize_t Py_ssize_clean_t; -#else -typedef int Py_ssize_clean_t; -#endif - -/* Largest possible value of size_t. - SIZE_MAX is part of C99, so it might be defined on some - platforms. If it is not defined, (size_t)-1 is a portable - definition for C89, due to the way signed->unsigned - conversion is defined. */ -#ifdef SIZE_MAX -#define PY_SIZE_MAX SIZE_MAX -#else -#define PY_SIZE_MAX ((size_t)-1) -#endif - -/* Largest positive value of type Py_ssize_t. */ -#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1)) -/* Smallest negative value of type Py_ssize_t. */ -#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1) - -/* PY_FORMAT_SIZE_T is a platform-specific modifier for use in a printf - * format to convert an argument with the width of a size_t or Py_ssize_t. - * C99 introduced "z" for this purpose, but not all platforms support that; - * e.g., MS compilers use "I" instead. - * - * These "high level" Python format functions interpret "z" correctly on - * all platforms (Python interprets the format string itself, and does whatever - * the platform C requires to convert a size_t/Py_ssize_t argument): - * - * PyBytes_FromFormat - * PyErr_Format - * PyBytes_FromFormatV - * PyUnicode_FromFormatV - * - * Lower-level uses require that you interpolate the correct format modifier - * yourself (e.g., calling printf, fprintf, sprintf, PyOS_snprintf); for - * example, - * - * Py_ssize_t index; - * fprintf(stderr, "index %" PY_FORMAT_SIZE_T "d sucks\n", index); - * - * That will expand to %ld, or %Id, or to something else correct for a - * Py_ssize_t on the platform. - */ -#ifndef PY_FORMAT_SIZE_T -# if SIZEOF_SIZE_T == SIZEOF_INT && !defined(__APPLE__) -# define PY_FORMAT_SIZE_T "" -# elif SIZEOF_SIZE_T == SIZEOF_LONG -# define PY_FORMAT_SIZE_T "l" -# elif defined(MS_WINDOWS) -# define PY_FORMAT_SIZE_T "I" -# else -# error "This platform's pyconfig.h needs to define PY_FORMAT_SIZE_T" -# endif -#endif - -/* PY_FORMAT_LONG_LONG is analogous to PY_FORMAT_SIZE_T above, but for - * the long long type instead of the size_t type. It's only available - * when HAVE_LONG_LONG is defined. The "high level" Python format - * functions listed above will interpret "lld" or "llu" correctly on - * all platforms. - */ -#ifdef HAVE_LONG_LONG -# ifndef PY_FORMAT_LONG_LONG -# ifdef MS_WINDOWS -# define PY_FORMAT_LONG_LONG "I64" -# else -# error "This platform's pyconfig.h needs to define PY_FORMAT_LONG_LONG" -# endif -# endif -#endif - -/* Py_LOCAL can be used instead of static to get the fastest possible calling - * convention for functions that are local to a given module. - * - * Py_LOCAL_INLINE does the same thing, and also explicitly requests inlining, - * for platforms that support that. - * - * If PY_LOCAL_AGGRESSIVE is defined before python.h is included, more - * "aggressive" inlining/optimization is enabled for the entire module. This - * may lead to code bloat, and may slow things down for those reasons. It may - * also lead to errors, if the code relies on pointer aliasing. Use with - * care. - * - * NOTE: You can only use this for functions that are entirely local to a - * module; functions that are exported via method tables, callbacks, etc, - * should keep using static. - */ - -#if defined(_MSC_VER) -#if defined(PY_LOCAL_AGGRESSIVE) -/* enable more aggressive optimization for visual studio */ -#pragma optimize("agtw", on) -#endif -/* ignore warnings if the compiler decides not to inline a function */ -#pragma warning(disable: 4710) -/* fastest possible local call under MSVC */ -#define Py_LOCAL(type) static type __fastcall -#define Py_LOCAL_INLINE(type) static __inline type __fastcall -#elif defined(USE_INLINE) -#define Py_LOCAL(type) static type -#define Py_LOCAL_INLINE(type) static inline type -#else -#define Py_LOCAL(type) static type -#define Py_LOCAL_INLINE(type) static type -#endif - -/* Py_MEMCPY can be used instead of memcpy in cases where the copied blocks - * are often very short. While most platforms have highly optimized code for - * large transfers, the setup costs for memcpy are often quite high. MEMCPY - * solves this by doing short copies "in line". - */ - -#if defined(_MSC_VER) -#define Py_MEMCPY(target, source, length) do { \ - size_t i_, n_ = (length); \ - char *t_ = (void*) (target); \ - const char *s_ = (void*) (source); \ - if (n_ >= 16) \ - memcpy(t_, s_, n_); \ - else \ - for (i_ = 0; i_ < n_; i_++) \ - t_[i_] = s_[i_]; \ - } while (0) -#else -#define Py_MEMCPY memcpy -#endif - -#include - -#ifdef HAVE_IEEEFP_H -#include /* needed for 'finite' declaration on some platforms */ -#endif - -#include /* Moved here from the math section, before extern "C" */ - -/******************************************** - * WRAPPER FOR and/or * - ********************************************/ - -#ifdef TIME_WITH_SYS_TIME -#include -#include -#else /* !TIME_WITH_SYS_TIME */ -#ifdef HAVE_SYS_TIME_H -#include -#else /* !HAVE_SYS_TIME_H */ -#include -#endif /* !HAVE_SYS_TIME_H */ -#endif /* !TIME_WITH_SYS_TIME */ - - -/****************************** - * WRAPPER FOR * - ******************************/ - -/* NB caller must include */ - -#ifdef HAVE_SYS_SELECT_H -#include -#endif /* !HAVE_SYS_SELECT_H */ - -/******************************* - * stat() and fstat() fiddling * - *******************************/ - -#ifdef HAVE_SYS_STAT_H -#include -#elif defined(HAVE_STAT_H) -#include -#endif - -#ifndef S_IFMT -/* VisualAge C/C++ Failed to Define MountType Field in sys/stat.h */ -#define S_IFMT 0170000 -#endif - -#ifndef S_IFLNK -/* Windows doesn't define S_IFLNK but posixmodule.c maps - * IO_REPARSE_TAG_SYMLINK to S_IFLNK */ -# define S_IFLNK 0120000 -#endif - -#ifndef S_ISREG -#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISCHR -#define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR) -#endif - -#ifdef __cplusplus -/* Move this down here since some C++ #include's don't like to be included - inside an extern "C" */ -extern "C" { -#endif - - -/* Py_ARITHMETIC_RIGHT_SHIFT - * C doesn't define whether a right-shift of a signed integer sign-extends - * or zero-fills. Here a macro to force sign extension: - * Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) - * Return I >> J, forcing sign extension. Arithmetically, return the - * floor of I/2**J. - * Requirements: - * I should have signed integer type. In the terminology of C99, this can - * be either one of the five standard signed integer types (signed char, - * short, int, long, long long) or an extended signed integer type. - * J is an integer >= 0 and strictly less than the number of bits in the - * type of I (because C doesn't define what happens for J outside that - * range either). - * TYPE used to specify the type of I, but is now ignored. It's been left - * in for backwards compatibility with versions <= 2.6 or 3.0. - * Caution: - * I may be evaluated more than once. - */ -#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS -#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \ - ((I) < 0 ? -1-((-1-(I)) >> (J)) : (I) >> (J)) -#else -#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J)) -#endif - -/* Py_FORCE_EXPANSION(X) - * "Simply" returns its argument. However, macro expansions within the - * argument are evaluated. This unfortunate trickery is needed to get - * token-pasting to work as desired in some cases. - */ -#define Py_FORCE_EXPANSION(X) X - -/* Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) - * Cast VALUE to type NARROW from type WIDE. In Py_DEBUG mode, this - * assert-fails if any information is lost. - * Caution: - * VALUE may be evaluated more than once. - */ -#ifdef Py_DEBUG -#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) \ - (assert((WIDE)(NARROW)(VALUE) == (VALUE)), (NARROW)(VALUE)) -#else -#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE) -#endif - -/* Py_SET_ERRNO_ON_MATH_ERROR(x) - * If a libm function did not set errno, but it looks like the result - * overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno - * to 0 before calling a libm function, and invoke this macro after, - * passing the function result. - * Caution: - * This isn't reliable. See Py_OVERFLOWED comments. - * X is evaluated more than once. - */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64)) -#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM; -#else -#define _Py_SET_EDOM_FOR_NAN(X) ; -#endif -#define Py_SET_ERRNO_ON_MATH_ERROR(X) \ - do { \ - if (errno == 0) { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ - errno = ERANGE; \ - else _Py_SET_EDOM_FOR_NAN(X) \ - } \ - } while(0) - -/* Py_SET_ERANGE_ON_OVERFLOW(x) - * An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility. - */ -#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X) - -/* Py_ADJUST_ERANGE1(x) - * Py_ADJUST_ERANGE2(x, y) - * Set errno to 0 before calling a libm function, and invoke one of these - * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful - * for functions returning complex results). This makes two kinds of - * adjustments to errno: (A) If it looks like the platform libm set - * errno=ERANGE due to underflow, clear errno. (B) If it looks like the - * platform libm overflowed but didn't set errno, force errno to ERANGE. In - * effect, we're trying to force a useful implementation of C89 errno - * behavior. - * Caution: - * This isn't reliable. See Py_OVERFLOWED comments. - * X and Y may be evaluated more than once. - */ -#define Py_ADJUST_ERANGE1(X) \ - do { \ - if (errno == 0) { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ - errno = ERANGE; \ - } \ - else if (errno == ERANGE && (X) == 0.0) \ - errno = 0; \ - } while(0) - -#define Py_ADJUST_ERANGE2(X, Y) \ - do { \ - if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \ - (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \ - if (errno == 0) \ - errno = ERANGE; \ - } \ - else if (errno == ERANGE) \ - errno = 0; \ - } while(0) - -/* The functions _Py_dg_strtod and _Py_dg_dtoa in Python/dtoa.c (which are - * required to support the short float repr introduced in Python 3.1) require - * that the floating-point unit that's being used for arithmetic operations - * on C doubles is set to use 53-bit precision. It also requires that the - * FPU rounding mode is round-half-to-even, but that's less often an issue. - * - * If your FPU isn't already set to 53-bit precision/round-half-to-even, and - * you want to make use of _Py_dg_strtod and _Py_dg_dtoa, then you should - * - * #define HAVE_PY_SET_53BIT_PRECISION 1 - * - * and also give appropriate definitions for the following three macros: - * - * _PY_SET_53BIT_PRECISION_START : store original FPU settings, and - * set FPU to 53-bit precision/round-half-to-even - * _PY_SET_53BIT_PRECISION_END : restore original FPU settings - * _PY_SET_53BIT_PRECISION_HEADER : any variable declarations needed to - * use the two macros above. - * - * The macros are designed to be used within a single C function: see - * Python/pystrtod.c for an example of their use. - */ - -/* get and set x87 control word for gcc/x86 */ -#ifdef HAVE_GCC_ASM_FOR_X87 -#define HAVE_PY_SET_53BIT_PRECISION 1 -/* _Py_get/set_387controlword functions are defined in Python/pymath.c */ -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned short old_387controlword, new_387controlword -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - old_387controlword = _Py_get_387controlword(); \ - new_387controlword = (old_387controlword & ~0x0f00) | 0x0200; \ - if (new_387controlword != old_387controlword) \ - _Py_set_387controlword(new_387controlword); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - if (new_387controlword != old_387controlword) \ - _Py_set_387controlword(old_387controlword) -#endif - -/* get and set x87 control word for VisualStudio/x86 */ -#if defined(_MSC_VER) && !defined(_WIN64) /* x87 not supported in 64-bit */ -#define HAVE_PY_SET_53BIT_PRECISION 1 -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned int old_387controlword, new_387controlword, out_387controlword -/* We use the __control87_2 function to set only the x87 control word. - The SSE control word is unaffected. */ -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - __control87_2(0, 0, &old_387controlword, NULL); \ - new_387controlword = \ - (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \ - if (new_387controlword != old_387controlword) \ - __control87_2(new_387controlword, _MCW_PC | _MCW_RC, \ - &out_387controlword, NULL); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - do { \ - if (new_387controlword != old_387controlword) \ - __control87_2(old_387controlword, _MCW_PC | _MCW_RC, \ - &out_387controlword, NULL); \ - } while (0) -#endif - -#ifdef HAVE_GCC_ASM_FOR_MC68881 -#define HAVE_PY_SET_53BIT_PRECISION 1 -#define _Py_SET_53BIT_PRECISION_HEADER \ - unsigned int old_fpcr, new_fpcr -#define _Py_SET_53BIT_PRECISION_START \ - do { \ - __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr)); \ - /* Set double precision / round to nearest. */ \ - new_fpcr = (old_fpcr & ~0xf0) | 0x80; \ - if (new_fpcr != old_fpcr) \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr)); \ - } while (0) -#define _Py_SET_53BIT_PRECISION_END \ - do { \ - if (new_fpcr != old_fpcr) \ - __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr)); \ - } while (0) -#endif - -/* default definitions are empty */ -#ifndef HAVE_PY_SET_53BIT_PRECISION -#define _Py_SET_53BIT_PRECISION_HEADER -#define _Py_SET_53BIT_PRECISION_START -#define _Py_SET_53BIT_PRECISION_END -#endif - -/* If we can't guarantee 53-bit precision, don't use the code - in Python/dtoa.c, but fall back to standard code. This - means that repr of a float will be long (17 sig digits). - - Realistically, there are two things that could go wrong: - - (1) doubles aren't IEEE 754 doubles, or - (2) we're on x86 with the rounding precision set to 64-bits - (extended precision), and we don't know how to change - the rounding precision. - */ - -#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \ - !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \ - !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754) -#define PY_NO_SHORT_FLOAT_REPR -#endif - -/* double rounding is symptomatic of use of extended precision on x86. If - we're seeing double rounding, and we don't have any mechanism available for - changing the FPU rounding precision, then don't use Python/dtoa.c. */ -#if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION) -#define PY_NO_SHORT_FLOAT_REPR -#endif - - -/* Py_DEPRECATED(version) - * Declare a variable, type, or function deprecated. - * Usage: - * extern int old_var Py_DEPRECATED(2.3); - * typedef int T1 Py_DEPRECATED(2.4); - * extern int x() Py_DEPRECATED(2.5); - */ -#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ - (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) -#define Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__)) -#else -#define Py_DEPRECATED(VERSION_UNUSED) -#endif - -/************************************************************************** -Prototypes that are missing from the standard include files on some systems -(and possibly only some versions of such systems.) - -Please be conservative with adding new ones, document them and enclose them -in platform-specific #ifdefs. -**************************************************************************/ - -#ifdef SOLARIS -/* Unchecked */ -extern int gethostname(char *, int); -#endif - -#ifdef HAVE__GETPTY -#include /* we need to import mode_t */ -extern char * _getpty(int *, int, mode_t, int); -#endif - -/* On QNX 6, struct termio must be declared by including sys/termio.h - if TCGETA, TCSETA, TCSETAW, or TCSETAF are used. sys/termio.h must - be included before termios.h or it will generate an error. */ -#if defined(HAVE_SYS_TERMIO_H) && !defined(__hpux) -#include -#endif - -#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) -#if !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) -/* BSDI does not supply a prototype for the 'openpty' and 'forkpty' - functions, even though they are included in libutil. */ -#include -extern int openpty(int *, int *, char *, struct termios *, struct winsize *); -extern pid_t forkpty(int *, char *, struct termios *, struct winsize *); -#endif /* !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) */ -#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) */ - - -/* On 4.4BSD-descendants, ctype functions serves the whole range of - * wchar_t character set rather than single byte code points only. - * This characteristic can break some operations of string object - * including str.upper() and str.split() on UTF-8 locales. This - * workaround was provided by Tim Robbins of FreeBSD project. - */ - -#ifdef __FreeBSD__ -#include -#if (__FreeBSD_version >= 500040 && __FreeBSD_version < 602113) || \ - (__FreeBSD_version >= 700000 && __FreeBSD_version < 700054) || \ - (__FreeBSD_version >= 800000 && __FreeBSD_version < 800001) -# define _PY_PORT_CTYPE_UTF8_ISSUE -#endif -#endif - - -#if defined(__APPLE__) -# define _PY_PORT_CTYPE_UTF8_ISSUE -#endif - -#ifdef _PY_PORT_CTYPE_UTF8_ISSUE -#ifndef __cplusplus - /* The workaround below is unsafe in C++ because - * the defines these symbols as real functions, - * with a slightly different signature. - * See issue #10910 - */ -#include -#include -#undef isalnum -#define isalnum(c) iswalnum(btowc(c)) -#undef isalpha -#define isalpha(c) iswalpha(btowc(c)) -#undef islower -#define islower(c) iswlower(btowc(c)) -#undef isspace -#define isspace(c) iswspace(btowc(c)) -#undef isupper -#define isupper(c) iswupper(btowc(c)) -#undef tolower -#define tolower(c) towlower(btowc(c)) -#undef toupper -#define toupper(c) towupper(btowc(c)) -#endif -#endif - - -/* Declarations for symbol visibility. - - PyAPI_FUNC(type): Declares a public Python API function and return type - PyAPI_DATA(type): Declares public Python data and its type - PyMODINIT_FUNC: A Python module init function. If these functions are - inside the Python core, they are private to the core. - If in an extension module, it may be declared with - external linkage depending on the platform. - - As a number of platforms support/require "__declspec(dllimport/dllexport)", - we support a HAVE_DECLSPEC_DLL macro to save duplication. -*/ - -/* - All windows ports, except cygwin, are handled in PC/pyconfig.h. - - Cygwin is the only other autoconf platform requiring special - linkage handling and it uses __declspec(). -*/ -#if defined(__CYGWIN__) -# define HAVE_DECLSPEC_DLL -#endif - -/* only get special linkage if built as shared or platform is Cygwin */ -#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) -# if defined(HAVE_DECLSPEC_DLL) -# ifdef Py_BUILD_CORE -# define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE -# define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE - /* module init functions inside the core need no external linkage */ - /* except for Cygwin to handle embedding */ -# if defined(__CYGWIN__) -# define PyMODINIT_FUNC __declspec(dllexport) PyObject* -# else /* __CYGWIN__ */ -# define PyMODINIT_FUNC PyObject* -# endif /* __CYGWIN__ */ -# else /* Py_BUILD_CORE */ - /* Building an extension module, or an embedded situation */ - /* public Python functions and data are imported */ - /* Under Cygwin, auto-import functions to prevent compilation */ - /* failures similar to those described at the bottom of 4.1: */ - /* http://docs.python.org/extending/windows.html#a-cookbook-approach */ -# if !defined(__CYGWIN__) -# define PyAPI_FUNC(RTYPE) __declspec(dllimport) RTYPE -# endif /* !__CYGWIN__ */ -# define PyAPI_DATA(RTYPE) extern __declspec(dllimport) RTYPE - /* module init functions outside the core must be exported */ -# if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" __declspec(dllexport) PyObject* -# else /* __cplusplus */ -# define PyMODINIT_FUNC __declspec(dllexport) PyObject* -# endif /* __cplusplus */ -# endif /* Py_BUILD_CORE */ -# endif /* HAVE_DECLSPEC */ -#endif /* Py_ENABLE_SHARED */ - -/* If no external linkage macros defined by now, create defaults */ -#ifndef PyAPI_FUNC -# define PyAPI_FUNC(RTYPE) RTYPE -#endif -#ifndef PyAPI_DATA -# define PyAPI_DATA(RTYPE) extern RTYPE -#endif -#ifndef PyMODINIT_FUNC -# if defined(__cplusplus) -# define PyMODINIT_FUNC extern "C" PyObject* -# else /* __cplusplus */ -# define PyMODINIT_FUNC PyObject* -# endif /* __cplusplus */ -#endif - -/* limits.h constants that may be missing */ - -#ifndef INT_MAX -#define INT_MAX 2147483647 -#endif - -#ifndef LONG_MAX -#if SIZEOF_LONG == 4 -#define LONG_MAX 0X7FFFFFFFL -#elif SIZEOF_LONG == 8 -#define LONG_MAX 0X7FFFFFFFFFFFFFFFL -#else -#error "could not set LONG_MAX in pyport.h" -#endif -#endif - -#ifndef LONG_MIN -#define LONG_MIN (-LONG_MAX-1) -#endif - -#ifndef LONG_BIT -#define LONG_BIT (8 * SIZEOF_LONG) -#endif - -#if LONG_BIT != 8 * SIZEOF_LONG -/* 04-Oct-2000 LONG_BIT is apparently (mis)defined as 64 on some recent - * 32-bit platforms using gcc. We try to catch that here at compile-time - * rather than waiting for integer multiplication to trigger bogus - * overflows. - */ -#error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)." -#endif - -#ifdef __cplusplus -} -#endif - -/* - * Hide GCC attributes from compilers that don't support them. - */ -#if (!defined(__GNUC__) || __GNUC__ < 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ) -#define Py_GCC_ATTRIBUTE(x) -#else -#define Py_GCC_ATTRIBUTE(x) __attribute__(x) -#endif - -/* - * Specify alignment on compilers that support it. - */ -#if defined(__GNUC__) && __GNUC__ >= 3 -#define Py_ALIGNED(x) __attribute__((aligned(x))) -#else -#define Py_ALIGNED(x) -#endif - -/* Eliminate end-of-loop code not reached warnings from SunPro C - * when using do{...}while(0) macros - */ -#ifdef __SUNPRO_C -#pragma error_messages (off,E_END_OF_LOOP_CODE_NOT_REACHED) -#endif - -/* - * Older Microsoft compilers don't support the C99 long long literal suffixes, - * so these will be defined in PC/pyconfig.h for those compilers. - */ -#ifndef Py_LL -#define Py_LL(x) x##LL -#endif - -#ifndef Py_ULL -#define Py_ULL(x) Py_LL(x##U) -#endif - -#ifdef VA_LIST_IS_ARRAY -#define Py_VA_COPY(x, y) Py_MEMCPY((x), (y), sizeof(va_list)) -#else -#ifdef __va_copy -#define Py_VA_COPY __va_copy -#else -#define Py_VA_COPY(x, y) (x) = (y) -#endif -#endif - -/* - * Convenient macros to deal with endianness of the platform. WORDS_BIGENDIAN is - * detected by configure and defined in pyconfig.h. The code in pyconfig.h - * also takes care of Apple's universal builds. - */ - -#ifdef WORDS_BIGENDIAN -#define PY_BIG_ENDIAN 1 -#define PY_LITTLE_ENDIAN 0 -#else -#define PY_BIG_ENDIAN 0 -#define PY_LITTLE_ENDIAN 1 -#endif - -#ifdef Py_BUILD_CORE -/* - * Macros to protect CRT calls against instant termination when passed an - * invalid parameter (issue23524). - */ -#if defined _MSC_VER && _MSC_VER >= 1900 - -extern _invalid_parameter_handler _Py_silent_invalid_parameter_handler; -#define _Py_BEGIN_SUPPRESS_IPH { _invalid_parameter_handler _Py_old_handler = \ - _set_thread_local_invalid_parameter_handler(_Py_silent_invalid_parameter_handler); -#define _Py_END_SUPPRESS_IPH _set_thread_local_invalid_parameter_handler(_Py_old_handler); } - -#else - -#define _Py_BEGIN_SUPPRESS_IPH -#define _Py_END_SUPPRESS_IPH - -#endif /* _MSC_VER >= 1900 */ -#endif /* Py_BUILD_CORE */ - -#endif /* Py_PYPORT_H */ +#ifndef Py_PYPORT_H +#define Py_PYPORT_H + +#include "pyconfig.h" /* include for defines */ + +/* Some versions of HP-UX & Solaris need inttypes.h for int32_t, + INT32_MAX, etc. */ +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +/************************************************************************** +Symbols and macros to supply platform-independent interfaces to basic +C language & library operations whose spellings vary across platforms. + +Please try to make documentation here as clear as possible: by definition, +the stuff here is trying to illuminate C's darkest corners. + +Config #defines referenced here: + +SIGNED_RIGHT_SHIFT_ZERO_FILLS +Meaning: To be defined iff i>>j does not extend the sign bit when i is a + signed integral type and i < 0. +Used in: Py_ARITHMETIC_RIGHT_SHIFT + +Py_DEBUG +Meaning: Extra checks compiled in for debug mode. +Used in: Py_SAFE_DOWNCAST + +HAVE_UINTPTR_T +Meaning: The C9X type uintptr_t is supported by the compiler +Used in: Py_uintptr_t + +HAVE_LONG_LONG +Meaning: The compiler supports the C type "long long" +Used in: PY_LONG_LONG + +**************************************************************************/ + +/* typedefs for some C9X-defined synonyms for integral types. + * + * The names in Python are exactly the same as the C9X names, except with a + * Py_ prefix. Until C9X is universally implemented, this is the only way + * to ensure that Python gets reliable names that don't conflict with names + * in non-Python code that are playing their own tricks to define the C9X + * names. + * + * NOTE: don't go nuts here! Python has no use for *most* of the C9X + * integral synonyms. Only define the ones we actually need. + */ + +#ifdef HAVE_LONG_LONG +#ifndef PY_LONG_LONG +#define PY_LONG_LONG long long +#if defined(LLONG_MAX) +/* If LLONG_MAX is defined in limits.h, use that. */ +#define PY_LLONG_MIN LLONG_MIN +#define PY_LLONG_MAX LLONG_MAX +#define PY_ULLONG_MAX ULLONG_MAX +#elif defined(__LONG_LONG_MAX__) +/* Otherwise, if GCC has a builtin define, use that. (Definition of + * PY_LLONG_MIN assumes two's complement with no trap representation.) */ +#define PY_LLONG_MAX __LONG_LONG_MAX__ +#define PY_LLONG_MIN (-PY_LLONG_MAX - 1) +#define PY_ULLONG_MAX (PY_LLONG_MAX * Py_ULL(2) + 1) +#elif defined(SIZEOF_LONG_LONG) +/* Otherwise compute from SIZEOF_LONG_LONG, assuming two's complement, no + padding bits, and no trap representation. Note: PY_ULLONG_MAX was + previously #defined as (~0ULL) here; but that'll give the wrong value in a + preprocessor expression on systems where long long != intmax_t. */ +#define PY_LLONG_MAX \ + (1 + 2 * ((Py_LL(1) << (CHAR_BIT * SIZEOF_LONG_LONG - 2)) - 1)) +#define PY_LLONG_MIN (-PY_LLONG_MAX - 1) +#define PY_ULLONG_MAX (PY_LLONG_MAX * Py_ULL(2) + 1) +#endif /* LLONG_MAX */ +#endif +#endif /* HAVE_LONG_LONG */ + +/* a build with 30-bit digits for Python integers needs an exact-width + * 32-bit unsigned integer type to store those digits. (We could just use + * type 'unsigned long', but that would be wasteful on a system where longs + * are 64-bits.) On Unix systems, the autoconf macro AC_TYPE_UINT32_T defines + * uint32_t to be such a type unless stdint.h or inttypes.h defines uint32_t. + * However, it doesn't set HAVE_UINT32_T, so we do that here. + */ +#ifdef uint32_t +#define HAVE_UINT32_T 1 +#endif + +#ifdef HAVE_UINT32_T +#ifndef PY_UINT32_T +#define PY_UINT32_T uint32_t +#endif +#endif + +/* Macros for a 64-bit unsigned integer type; used for type 'twodigits' in the + * integer implementation, when 30-bit digits are enabled. + */ +#ifdef uint64_t +#define HAVE_UINT64_T 1 +#endif + +#ifdef HAVE_UINT64_T +#ifndef PY_UINT64_T +#define PY_UINT64_T uint64_t +#endif +#endif + +/* Signed variants of the above */ +#ifdef int32_t +#define HAVE_INT32_T 1 +#endif + +#ifdef HAVE_INT32_T +#ifndef PY_INT32_T +#define PY_INT32_T int32_t +#endif +#endif + +#ifdef int64_t +#define HAVE_INT64_T 1 +#endif + +#ifdef HAVE_INT64_T +#ifndef PY_INT64_T +#define PY_INT64_T int64_t +#endif +#endif + +/* If PYLONG_BITS_IN_DIGIT is not defined then we'll use 30-bit digits if all + the necessary integer types are available, and we're on a 64-bit platform + (as determined by SIZEOF_VOID_P); otherwise we use 15-bit digits. */ + +#ifndef PYLONG_BITS_IN_DIGIT +#if (defined HAVE_UINT64_T && defined HAVE_INT64_T && \ + defined HAVE_UINT32_T && defined HAVE_INT32_T && SIZEOF_VOID_P >= 8) +#define PYLONG_BITS_IN_DIGIT 30 +#else +#define PYLONG_BITS_IN_DIGIT 15 +#endif +#endif + +/* uintptr_t is the C9X name for an unsigned integral type such that a + * legitimate void* can be cast to uintptr_t and then back to void* again + * without loss of information. Similarly for intptr_t, wrt a signed + * integral type. + */ +#ifdef HAVE_UINTPTR_T +typedef uintptr_t Py_uintptr_t; +typedef intptr_t Py_intptr_t; + +#elif SIZEOF_VOID_P <= SIZEOF_INT +typedef unsigned int Py_uintptr_t; +typedef int Py_intptr_t; + +#elif SIZEOF_VOID_P <= SIZEOF_LONG +typedef unsigned long Py_uintptr_t; +typedef long Py_intptr_t; + +#elif defined(HAVE_LONG_LONG) && (SIZEOF_VOID_P <= SIZEOF_LONG_LONG) +typedef unsigned PY_LONG_LONG Py_uintptr_t; +typedef PY_LONG_LONG Py_intptr_t; + +#else +# error "Python needs a typedef for Py_uintptr_t in pyport.h." +#endif /* HAVE_UINTPTR_T */ + +/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == + * sizeof(size_t). C99 doesn't define such a thing directly (size_t is an + * unsigned integral type). See PEP 353 for details. + */ +#ifdef HAVE_SSIZE_T +typedef ssize_t Py_ssize_t; +#elif SIZEOF_VOID_P == SIZEOF_SIZE_T +typedef Py_intptr_t Py_ssize_t; +#else +# error "Python needs a typedef for Py_ssize_t in pyport.h." +#endif + +/* Py_hash_t is the same size as a pointer. */ +#define SIZEOF_PY_HASH_T SIZEOF_SIZE_T +typedef Py_ssize_t Py_hash_t; +/* Py_uhash_t is the unsigned equivalent needed to calculate numeric hash. */ +#define SIZEOF_PY_UHASH_T SIZEOF_SIZE_T +typedef size_t Py_uhash_t; + +/* Only used for compatibility with code that may not be PY_SSIZE_T_CLEAN. */ +#ifdef PY_SSIZE_T_CLEAN +typedef Py_ssize_t Py_ssize_clean_t; +#else +typedef int Py_ssize_clean_t; +#endif + +/* Largest possible value of size_t. + SIZE_MAX is part of C99, so it might be defined on some + platforms. If it is not defined, (size_t)-1 is a portable + definition for C89, due to the way signed->unsigned + conversion is defined. */ +#ifdef SIZE_MAX +#define PY_SIZE_MAX SIZE_MAX +#else +#define PY_SIZE_MAX ((size_t)-1) +#endif + +/* Largest positive value of type Py_ssize_t. */ +#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1)) +/* Smallest negative value of type Py_ssize_t. */ +#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1) + +/* PY_FORMAT_SIZE_T is a platform-specific modifier for use in a printf + * format to convert an argument with the width of a size_t or Py_ssize_t. + * C99 introduced "z" for this purpose, but not all platforms support that; + * e.g., MS compilers use "I" instead. + * + * These "high level" Python format functions interpret "z" correctly on + * all platforms (Python interprets the format string itself, and does whatever + * the platform C requires to convert a size_t/Py_ssize_t argument): + * + * PyBytes_FromFormat + * PyErr_Format + * PyBytes_FromFormatV + * PyUnicode_FromFormatV + * + * Lower-level uses require that you interpolate the correct format modifier + * yourself (e.g., calling printf, fprintf, sprintf, PyOS_snprintf); for + * example, + * + * Py_ssize_t index; + * fprintf(stderr, "index %" PY_FORMAT_SIZE_T "d sucks\n", index); + * + * That will expand to %ld, or %Id, or to something else correct for a + * Py_ssize_t on the platform. + */ +#ifndef PY_FORMAT_SIZE_T +# if SIZEOF_SIZE_T == SIZEOF_INT && !defined(__APPLE__) +# define PY_FORMAT_SIZE_T "" +# elif SIZEOF_SIZE_T == SIZEOF_LONG +# define PY_FORMAT_SIZE_T "l" +# elif defined(MS_WINDOWS) +# define PY_FORMAT_SIZE_T "I" +# else +# error "This platform's pyconfig.h needs to define PY_FORMAT_SIZE_T" +# endif +#endif + +/* PY_FORMAT_LONG_LONG is analogous to PY_FORMAT_SIZE_T above, but for + * the long long type instead of the size_t type. It's only available + * when HAVE_LONG_LONG is defined. The "high level" Python format + * functions listed above will interpret "lld" or "llu" correctly on + * all platforms. + */ +#ifdef HAVE_LONG_LONG +# ifndef PY_FORMAT_LONG_LONG +# ifdef MS_WINDOWS +# define PY_FORMAT_LONG_LONG "I64" +# else +# error "This platform's pyconfig.h needs to define PY_FORMAT_LONG_LONG" +# endif +# endif +#endif + +/* Py_LOCAL can be used instead of static to get the fastest possible calling + * convention for functions that are local to a given module. + * + * Py_LOCAL_INLINE does the same thing, and also explicitly requests inlining, + * for platforms that support that. + * + * If PY_LOCAL_AGGRESSIVE is defined before python.h is included, more + * "aggressive" inlining/optimization is enabled for the entire module. This + * may lead to code bloat, and may slow things down for those reasons. It may + * also lead to errors, if the code relies on pointer aliasing. Use with + * care. + * + * NOTE: You can only use this for functions that are entirely local to a + * module; functions that are exported via method tables, callbacks, etc, + * should keep using static. + */ + +#if defined(_MSC_VER) +#if defined(PY_LOCAL_AGGRESSIVE) +/* enable more aggressive optimization for visual studio */ +#pragma optimize("agtw", on) +#endif +/* ignore warnings if the compiler decides not to inline a function */ +#pragma warning(disable: 4710) +/* fastest possible local call under MSVC */ +#define Py_LOCAL(type) static type __fastcall +#define Py_LOCAL_INLINE(type) static __inline type __fastcall +#elif defined(USE_INLINE) +#define Py_LOCAL(type) static type +#define Py_LOCAL_INLINE(type) static inline type +#else +#define Py_LOCAL(type) static type +#define Py_LOCAL_INLINE(type) static type +#endif + +/* Py_MEMCPY can be used instead of memcpy in cases where the copied blocks + * are often very short. While most platforms have highly optimized code for + * large transfers, the setup costs for memcpy are often quite high. MEMCPY + * solves this by doing short copies "in line". + */ + +#if defined(_MSC_VER) +#define Py_MEMCPY(target, source, length) do { \ + size_t i_, n_ = (length); \ + char *t_ = (void*) (target); \ + const char *s_ = (void*) (source); \ + if (n_ >= 16) \ + memcpy(t_, s_, n_); \ + else \ + for (i_ = 0; i_ < n_; i_++) \ + t_[i_] = s_[i_]; \ + } while (0) +#else +#define Py_MEMCPY memcpy +#endif + +#include + +#ifdef HAVE_IEEEFP_H +#include /* needed for 'finite' declaration on some platforms */ +#endif + +#include /* Moved here from the math section, before extern "C" */ + +/******************************************** + * WRAPPER FOR and/or * + ********************************************/ + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else /* !TIME_WITH_SYS_TIME */ +#ifdef HAVE_SYS_TIME_H +#include +#else /* !HAVE_SYS_TIME_H */ +#include +#endif /* !HAVE_SYS_TIME_H */ +#endif /* !TIME_WITH_SYS_TIME */ + + +/****************************** + * WRAPPER FOR * + ******************************/ + +/* NB caller must include */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* !HAVE_SYS_SELECT_H */ + +/******************************* + * stat() and fstat() fiddling * + *******************************/ + +#ifdef HAVE_SYS_STAT_H +#include +#elif defined(HAVE_STAT_H) +#include +#endif + +#ifndef S_IFMT +/* VisualAge C/C++ Failed to Define MountType Field in sys/stat.h */ +#define S_IFMT 0170000 +#endif + +#ifndef S_IFLNK +/* Windows doesn't define S_IFLNK but posixmodule.c maps + * IO_REPARSE_TAG_SYMLINK to S_IFLNK */ +# define S_IFLNK 0120000 +#endif + +#ifndef S_ISREG +#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISCHR +#define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR) +#endif + +#ifdef __cplusplus +/* Move this down here since some C++ #include's don't like to be included + inside an extern "C" */ +extern "C" { +#endif + + +/* Py_ARITHMETIC_RIGHT_SHIFT + * C doesn't define whether a right-shift of a signed integer sign-extends + * or zero-fills. Here a macro to force sign extension: + * Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) + * Return I >> J, forcing sign extension. Arithmetically, return the + * floor of I/2**J. + * Requirements: + * I should have signed integer type. In the terminology of C99, this can + * be either one of the five standard signed integer types (signed char, + * short, int, long, long long) or an extended signed integer type. + * J is an integer >= 0 and strictly less than the number of bits in the + * type of I (because C doesn't define what happens for J outside that + * range either). + * TYPE used to specify the type of I, but is now ignored. It's been left + * in for backwards compatibility with versions <= 2.6 or 3.0. + * Caution: + * I may be evaluated more than once. + */ +#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS +#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \ + ((I) < 0 ? -1-((-1-(I)) >> (J)) : (I) >> (J)) +#else +#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J)) +#endif + +/* Py_FORCE_EXPANSION(X) + * "Simply" returns its argument. However, macro expansions within the + * argument are evaluated. This unfortunate trickery is needed to get + * token-pasting to work as desired in some cases. + */ +#define Py_FORCE_EXPANSION(X) X + +/* Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) + * Cast VALUE to type NARROW from type WIDE. In Py_DEBUG mode, this + * assert-fails if any information is lost. + * Caution: + * VALUE may be evaluated more than once. + */ +#ifdef Py_DEBUG +#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) \ + (assert((WIDE)(NARROW)(VALUE) == (VALUE)), (NARROW)(VALUE)) +#else +#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE) +#endif + +/* Py_SET_ERRNO_ON_MATH_ERROR(x) + * If a libm function did not set errno, but it looks like the result + * overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno + * to 0 before calling a libm function, and invoke this macro after, + * passing the function result. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X is evaluated more than once. + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64)) +#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM; +#else +#define _Py_SET_EDOM_FOR_NAN(X) ; +#endif +#define Py_SET_ERRNO_ON_MATH_ERROR(X) \ + do { \ + if (errno == 0) { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ + errno = ERANGE; \ + else _Py_SET_EDOM_FOR_NAN(X) \ + } \ + } while(0) + +/* Py_SET_ERANGE_ON_OVERFLOW(x) + * An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility. + */ +#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X) + +/* Py_ADJUST_ERANGE1(x) + * Py_ADJUST_ERANGE2(x, y) + * Set errno to 0 before calling a libm function, and invoke one of these + * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful + * for functions returning complex results). This makes two kinds of + * adjustments to errno: (A) If it looks like the platform libm set + * errno=ERANGE due to underflow, clear errno. (B) If it looks like the + * platform libm overflowed but didn't set errno, force errno to ERANGE. In + * effect, we're trying to force a useful implementation of C89 errno + * behavior. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X and Y may be evaluated more than once. + */ +#define Py_ADJUST_ERANGE1(X) \ + do { \ + if (errno == 0) { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE && (X) == 0.0) \ + errno = 0; \ + } while(0) + +#define Py_ADJUST_ERANGE2(X, Y) \ + do { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \ + (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \ + if (errno == 0) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE) \ + errno = 0; \ + } while(0) + +/* The functions _Py_dg_strtod and _Py_dg_dtoa in Python/dtoa.c (which are + * required to support the short float repr introduced in Python 3.1) require + * that the floating-point unit that's being used for arithmetic operations + * on C doubles is set to use 53-bit precision. It also requires that the + * FPU rounding mode is round-half-to-even, but that's less often an issue. + * + * If your FPU isn't already set to 53-bit precision/round-half-to-even, and + * you want to make use of _Py_dg_strtod and _Py_dg_dtoa, then you should + * + * #define HAVE_PY_SET_53BIT_PRECISION 1 + * + * and also give appropriate definitions for the following three macros: + * + * _PY_SET_53BIT_PRECISION_START : store original FPU settings, and + * set FPU to 53-bit precision/round-half-to-even + * _PY_SET_53BIT_PRECISION_END : restore original FPU settings + * _PY_SET_53BIT_PRECISION_HEADER : any variable declarations needed to + * use the two macros above. + * + * The macros are designed to be used within a single C function: see + * Python/pystrtod.c for an example of their use. + */ + +/* get and set x87 control word for gcc/x86 */ +#ifdef HAVE_GCC_ASM_FOR_X87 +#define HAVE_PY_SET_53BIT_PRECISION 1 +/* _Py_get/set_387controlword functions are defined in Python/pymath.c */ +#define _Py_SET_53BIT_PRECISION_HEADER \ + unsigned short old_387controlword, new_387controlword +#define _Py_SET_53BIT_PRECISION_START \ + do { \ + old_387controlword = _Py_get_387controlword(); \ + new_387controlword = (old_387controlword & ~0x0f00) | 0x0200; \ + if (new_387controlword != old_387controlword) \ + _Py_set_387controlword(new_387controlword); \ + } while (0) +#define _Py_SET_53BIT_PRECISION_END \ + if (new_387controlword != old_387controlword) \ + _Py_set_387controlword(old_387controlword) +#endif + +/* get and set x87 control word for VisualStudio/x86 */ +#if defined(_MSC_VER) && !defined(_WIN64) /* x87 not supported in 64-bit */ +#define HAVE_PY_SET_53BIT_PRECISION 1 +#define _Py_SET_53BIT_PRECISION_HEADER \ + unsigned int old_387controlword, new_387controlword, out_387controlword +/* We use the __control87_2 function to set only the x87 control word. + The SSE control word is unaffected. */ +#define _Py_SET_53BIT_PRECISION_START \ + do { \ + __control87_2(0, 0, &old_387controlword, NULL); \ + new_387controlword = \ + (old_387controlword & ~(_MCW_PC | _MCW_RC)) | (_PC_53 | _RC_NEAR); \ + if (new_387controlword != old_387controlword) \ + __control87_2(new_387controlword, _MCW_PC | _MCW_RC, \ + &out_387controlword, NULL); \ + } while (0) +#define _Py_SET_53BIT_PRECISION_END \ + do { \ + if (new_387controlword != old_387controlword) \ + __control87_2(old_387controlword, _MCW_PC | _MCW_RC, \ + &out_387controlword, NULL); \ + } while (0) +#endif + +#ifdef HAVE_GCC_ASM_FOR_MC68881 +#define HAVE_PY_SET_53BIT_PRECISION 1 +#define _Py_SET_53BIT_PRECISION_HEADER \ + unsigned int old_fpcr, new_fpcr +#define _Py_SET_53BIT_PRECISION_START \ + do { \ + __asm__ ("fmove.l %%fpcr,%0" : "=g" (old_fpcr)); \ + /* Set double precision / round to nearest. */ \ + new_fpcr = (old_fpcr & ~0xf0) | 0x80; \ + if (new_fpcr != old_fpcr) \ + __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (new_fpcr)); \ + } while (0) +#define _Py_SET_53BIT_PRECISION_END \ + do { \ + if (new_fpcr != old_fpcr) \ + __asm__ volatile ("fmove.l %0,%%fpcr" : : "g" (old_fpcr)); \ + } while (0) +#endif + +/* default definitions are empty */ +#ifndef HAVE_PY_SET_53BIT_PRECISION +#define _Py_SET_53BIT_PRECISION_HEADER +#define _Py_SET_53BIT_PRECISION_START +#define _Py_SET_53BIT_PRECISION_END +#endif + +/* If we can't guarantee 53-bit precision, don't use the code + in Python/dtoa.c, but fall back to standard code. This + means that repr of a float will be long (17 sig digits). + + Realistically, there are two things that could go wrong: + + (1) doubles aren't IEEE 754 doubles, or + (2) we're on x86 with the rounding precision set to 64-bits + (extended precision), and we don't know how to change + the rounding precision. + */ + +#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \ + !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \ + !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754) +#define PY_NO_SHORT_FLOAT_REPR +#endif + +/* double rounding is symptomatic of use of extended precision on x86. If + we're seeing double rounding, and we don't have any mechanism available for + changing the FPU rounding precision, then don't use Python/dtoa.c. */ +#if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION) +#define PY_NO_SHORT_FLOAT_REPR +#endif + + +/* Py_DEPRECATED(version) + * Declare a variable, type, or function deprecated. + * Usage: + * extern int old_var Py_DEPRECATED(2.3); + * typedef int T1 Py_DEPRECATED(2.4); + * extern int x() Py_DEPRECATED(2.5); + */ +#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ + (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) +#define Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__)) +#else +#define Py_DEPRECATED(VERSION_UNUSED) +#endif + +/************************************************************************** +Prototypes that are missing from the standard include files on some systems +(and possibly only some versions of such systems.) + +Please be conservative with adding new ones, document them and enclose them +in platform-specific #ifdefs. +**************************************************************************/ + +#ifdef SOLARIS +/* Unchecked */ +extern int gethostname(char *, int); +#endif + +#ifdef HAVE__GETPTY +#include /* we need to import mode_t */ +extern char * _getpty(int *, int, mode_t, int); +#endif + +/* On QNX 6, struct termio must be declared by including sys/termio.h + if TCGETA, TCSETA, TCSETAW, or TCSETAF are used. sys/termio.h must + be included before termios.h or it will generate an error. */ +#if defined(HAVE_SYS_TERMIO_H) && !defined(__hpux) +#include +#endif + +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) +#if !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) +/* BSDI does not supply a prototype for the 'openpty' and 'forkpty' + functions, even though they are included in libutil. */ +#include +extern int openpty(int *, int *, char *, struct termios *, struct winsize *); +extern pid_t forkpty(int *, char *, struct termios *, struct winsize *); +#endif /* !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) */ +#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) */ + + +/* On 4.4BSD-descendants, ctype functions serves the whole range of + * wchar_t character set rather than single byte code points only. + * This characteristic can break some operations of string object + * including str.upper() and str.split() on UTF-8 locales. This + * workaround was provided by Tim Robbins of FreeBSD project. + */ + +#ifdef __FreeBSD__ +#include +#if (__FreeBSD_version >= 500040 && __FreeBSD_version < 602113) || \ + (__FreeBSD_version >= 700000 && __FreeBSD_version < 700054) || \ + (__FreeBSD_version >= 800000 && __FreeBSD_version < 800001) +# define _PY_PORT_CTYPE_UTF8_ISSUE +#endif +#endif + + +#if defined(__APPLE__) +# define _PY_PORT_CTYPE_UTF8_ISSUE +#endif + +#ifdef _PY_PORT_CTYPE_UTF8_ISSUE +#ifndef __cplusplus + /* The workaround below is unsafe in C++ because + * the defines these symbols as real functions, + * with a slightly different signature. + * See issue #10910 + */ +#include +#include +#undef isalnum +#define isalnum(c) iswalnum(btowc(c)) +#undef isalpha +#define isalpha(c) iswalpha(btowc(c)) +#undef islower +#define islower(c) iswlower(btowc(c)) +#undef isspace +#define isspace(c) iswspace(btowc(c)) +#undef isupper +#define isupper(c) iswupper(btowc(c)) +#undef tolower +#define tolower(c) towlower(btowc(c)) +#undef toupper +#define toupper(c) towupper(btowc(c)) +#endif +#endif + + +/* Declarations for symbol visibility. + + PyAPI_FUNC(type): Declares a public Python API function and return type + PyAPI_DATA(type): Declares public Python data and its type + PyMODINIT_FUNC: A Python module init function. If these functions are + inside the Python core, they are private to the core. + If in an extension module, it may be declared with + external linkage depending on the platform. + + As a number of platforms support/require "__declspec(dllimport/dllexport)", + we support a HAVE_DECLSPEC_DLL macro to save duplication. +*/ + +/* + All windows ports, except cygwin, are handled in PC/pyconfig.h. + + Cygwin is the only other autoconf platform requiring special + linkage handling and it uses __declspec(). +*/ +#if defined(__CYGWIN__) +# define HAVE_DECLSPEC_DLL +#endif + +/* only get special linkage if built as shared or platform is Cygwin */ +#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) +# if defined(HAVE_DECLSPEC_DLL) +# ifdef Py_BUILD_CORE +# define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE +# define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE + /* module init functions inside the core need no external linkage */ + /* except for Cygwin to handle embedding */ +# if defined(__CYGWIN__) +# define PyMODINIT_FUNC __declspec(dllexport) PyObject* +# else /* __CYGWIN__ */ +# define PyMODINIT_FUNC PyObject* +# endif /* __CYGWIN__ */ +# else /* Py_BUILD_CORE */ + /* Building an extension module, or an embedded situation */ + /* public Python functions and data are imported */ + /* Under Cygwin, auto-import functions to prevent compilation */ + /* failures similar to those described at the bottom of 4.1: */ + /* http://docs.python.org/extending/windows.html#a-cookbook-approach */ +# if !defined(__CYGWIN__) +# define PyAPI_FUNC(RTYPE) __declspec(dllimport) RTYPE +# endif /* !__CYGWIN__ */ +# define PyAPI_DATA(RTYPE) extern __declspec(dllimport) RTYPE + /* module init functions outside the core must be exported */ +# if defined(__cplusplus) +# define PyMODINIT_FUNC extern "C" __declspec(dllexport) PyObject* +# else /* __cplusplus */ +# define PyMODINIT_FUNC __declspec(dllexport) PyObject* +# endif /* __cplusplus */ +# endif /* Py_BUILD_CORE */ +# endif /* HAVE_DECLSPEC */ +#endif /* Py_ENABLE_SHARED */ + +/* If no external linkage macros defined by now, create defaults */ +#ifndef PyAPI_FUNC +# define PyAPI_FUNC(RTYPE) RTYPE +#endif +#ifndef PyAPI_DATA +# define PyAPI_DATA(RTYPE) extern RTYPE +#endif +#ifndef PyMODINIT_FUNC +# if defined(__cplusplus) +# define PyMODINIT_FUNC extern "C" PyObject* +# else /* __cplusplus */ +# define PyMODINIT_FUNC PyObject* +# endif /* __cplusplus */ +#endif + +/* limits.h constants that may be missing */ + +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif + +#ifndef LONG_MAX +#if SIZEOF_LONG == 4 +#define LONG_MAX 0X7FFFFFFFL +#elif SIZEOF_LONG == 8 +#define LONG_MAX 0X7FFFFFFFFFFFFFFFL +#else +#error "could not set LONG_MAX in pyport.h" +#endif +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#endif + +#ifndef LONG_BIT +#define LONG_BIT (8 * SIZEOF_LONG) +#endif + +#if LONG_BIT != 8 * SIZEOF_LONG +/* 04-Oct-2000 LONG_BIT is apparently (mis)defined as 64 on some recent + * 32-bit platforms using gcc. We try to catch that here at compile-time + * rather than waiting for integer multiplication to trigger bogus + * overflows. + */ +#error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)." +#endif + +#ifdef __cplusplus +} +#endif + +/* + * Hide GCC attributes from compilers that don't support them. + */ +#if (!defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ) +#define Py_GCC_ATTRIBUTE(x) +#else +#define Py_GCC_ATTRIBUTE(x) __attribute__(x) +#endif + +/* + * Specify alignment on compilers that support it. + */ +#if defined(__GNUC__) && __GNUC__ >= 3 +#define Py_ALIGNED(x) __attribute__((aligned(x))) +#else +#define Py_ALIGNED(x) +#endif + +/* Eliminate end-of-loop code not reached warnings from SunPro C + * when using do{...}while(0) macros + */ +#ifdef __SUNPRO_C +#pragma error_messages (off,E_END_OF_LOOP_CODE_NOT_REACHED) +#endif + +/* + * Older Microsoft compilers don't support the C99 long long literal suffixes, + * so these will be defined in PC/pyconfig.h for those compilers. + */ +#ifndef Py_LL +#define Py_LL(x) x##LL +#endif + +#ifndef Py_ULL +#define Py_ULL(x) Py_LL(x##U) +#endif + +#ifdef VA_LIST_IS_ARRAY +#define Py_VA_COPY(x, y) Py_MEMCPY((x), (y), sizeof(va_list)) +#else +#ifdef __va_copy +#define Py_VA_COPY __va_copy +#else +#define Py_VA_COPY(x, y) (x) = (y) +#endif +#endif + +/* + * Convenient macros to deal with endianness of the platform. WORDS_BIGENDIAN is + * detected by configure and defined in pyconfig.h. The code in pyconfig.h + * also takes care of Apple's universal builds. + */ + +#ifdef WORDS_BIGENDIAN +#define PY_BIG_ENDIAN 1 +#define PY_LITTLE_ENDIAN 0 +#else +#define PY_BIG_ENDIAN 0 +#define PY_LITTLE_ENDIAN 1 +#endif + +#ifdef Py_BUILD_CORE +/* + * Macros to protect CRT calls against instant termination when passed an + * invalid parameter (issue23524). + */ +#if defined _MSC_VER && _MSC_VER >= 1900 + +extern _invalid_parameter_handler _Py_silent_invalid_parameter_handler; +#define _Py_BEGIN_SUPPRESS_IPH { _invalid_parameter_handler _Py_old_handler = \ + _set_thread_local_invalid_parameter_handler(_Py_silent_invalid_parameter_handler); +#define _Py_END_SUPPRESS_IPH _set_thread_local_invalid_parameter_handler(_Py_old_handler); } + +#else + +#define _Py_BEGIN_SUPPRESS_IPH +#define _Py_END_SUPPRESS_IPH + +#endif /* _MSC_VER >= 1900 */ +#endif /* Py_BUILD_CORE */ + +#endif /* Py_PYPORT_H */ diff --git a/libs/nxpy/include/pystate.h b/libs/nxpy/include/pystate.h index cb1d2337..1cdb3b71 100644 --- a/libs/nxpy/include/pystate.h +++ b/libs/nxpy/include/pystate.h @@ -1,279 +1,279 @@ - -/* Thread and interpreter state structures and their interfaces */ - - -#ifndef Py_PYSTATE_H -#define Py_PYSTATE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* State shared between threads */ - -struct _ts; /* Forward */ -struct _is; /* Forward */ - -#ifdef Py_LIMITED_API -typedef struct _is PyInterpreterState; -#else -typedef struct _is { - - struct _is *next; - struct _ts *tstate_head; - - PyObject *modules; - PyObject *modules_by_index; - PyObject *sysdict; - PyObject *builtins; - PyObject *importlib; - - PyObject *codec_search_path; - PyObject *codec_search_cache; - PyObject *codec_error_registry; - int codecs_initialized; - int fscodec_initialized; - -#ifdef HAVE_DLOPEN - int dlopenflags; -#endif -#ifdef WITH_TSC - int tscdump; -#endif - - PyObject *builtins_copy; -} PyInterpreterState; -#endif - - -/* State unique per thread */ - -struct _frame; /* Avoid including frameobject.h */ - -#ifndef Py_LIMITED_API -/* Py_tracefunc return -1 when raising an exception, or 0 for success. */ -typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); - -/* The following values are used for 'what' for tracefunc functions: */ -#define PyTrace_CALL 0 -#define PyTrace_EXCEPTION 1 -#define PyTrace_LINE 2 -#define PyTrace_RETURN 3 -#define PyTrace_C_CALL 4 -#define PyTrace_C_EXCEPTION 5 -#define PyTrace_C_RETURN 6 -#endif - -#ifdef Py_LIMITED_API -typedef struct _ts PyThreadState; -#else -typedef struct _ts { - /* See Python/ceval.c for comments explaining most fields */ - - struct _ts *prev; - struct _ts *next; - PyInterpreterState *interp; - - struct _frame *frame; - int recursion_depth; - char overflowed; /* The stack has overflowed. Allow 50 more calls - to handle the runtime error. */ - char recursion_critical; /* The current calls must not cause - a stack overflow. */ - /* 'tracing' keeps track of the execution depth when tracing/profiling. - This is to prevent the actual trace/profile code from being recorded in - the trace/profile. */ - int tracing; - int use_tracing; - - Py_tracefunc c_profilefunc; - Py_tracefunc c_tracefunc; - PyObject *c_profileobj; - PyObject *c_traceobj; - - PyObject *curexc_type; - PyObject *curexc_value; - PyObject *curexc_traceback; - - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_traceback; - - PyObject *dict; /* Stores per-thread state */ - - int gilstate_counter; - - PyObject *async_exc; /* Asynchronous exception to raise */ - long thread_id; /* Thread id where this tstate was created */ - - int trash_delete_nesting; - PyObject *trash_delete_later; - - /* Called when a thread state is deleted normally, but not when it - * is destroyed after fork(). - * Pain: to prevent rare but fatal shutdown errors (issue 18808), - * Thread.join() must wait for the join'ed thread's tstate to be unlinked - * from the tstate chain. That happens at the end of a thread's life, - * in pystate.c. - * The obvious way doesn't quite work: create a lock which the tstate - * unlinking code releases, and have Thread.join() wait to acquire that - * lock. The problem is that we _are_ at the end of the thread's life: - * if the thread holds the last reference to the lock, decref'ing the - * lock will delete the lock, and that may trigger arbitrary Python code - * if there's a weakref, with a callback, to the lock. But by this time - * _PyThreadState_Current is already NULL, so only the simplest of C code - * can be allowed to run (in particular it must not be possible to - * release the GIL). - * So instead of holding the lock directly, the tstate holds a weakref to - * the lock: that's the value of on_delete_data below. Decref'ing a - * weakref is harmless. - * on_delete points to _threadmodule.c's static release_sentinel() function. - * After the tstate is unlinked, release_sentinel is called with the - * weakref-to-lock (on_delete_data) argument, and release_sentinel releases - * the indirectly held lock. - */ - void (*on_delete)(void *); - void *on_delete_data; - - PyObject *coroutine_wrapper; - int in_coroutine_wrapper; - - /* XXX signal handlers should also be here */ - -} PyThreadState; -#endif - - -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void); -PyAPI_FUNC(void) PyInterpreterState_Clear(PyInterpreterState *); -PyAPI_FUNC(void) PyInterpreterState_Delete(PyInterpreterState *); -PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -/* New in 3.3 */ -PyAPI_FUNC(int) PyState_AddModule(PyObject*, struct PyModuleDef*); -PyAPI_FUNC(int) PyState_RemoveModule(struct PyModuleDef*); -#endif -PyAPI_FUNC(PyObject*) PyState_FindModule(struct PyModuleDef*); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyState_ClearModules(void); -#endif - -PyAPI_FUNC(PyThreadState *) PyThreadState_New(PyInterpreterState *); -PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); -PyAPI_FUNC(void) _PyThreadState_Init(PyThreadState *); -PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *); -PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); -PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); -#ifdef WITH_THREAD -PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); -PyAPI_FUNC(void) _PyGILState_Reinit(void); -#endif - -/* Return the current thread state. The global interpreter lock must be held. - * When the current thread state is NULL, this issues a fatal error (so that - * the caller needn't check for NULL). */ -PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); - -/* Similar to PyThreadState_Get(), but don't issue a fatal error - * if it is NULL. */ -PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void); - -PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *); -PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void); -PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *); - - -/* Variable and macro for in-line access to current thread state */ - -/* Assuming the current thread holds the GIL, this is the - PyThreadState for the current thread. */ -#if defined(Py_BUILD_CORE) && !defined(__cplusplus) -PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; -# define PyThreadState_GET() \ - ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) -#else -# define PyThreadState_GET() PyThreadState_Get() -#endif - -typedef - enum {PyGILState_LOCKED, PyGILState_UNLOCKED} - PyGILState_STATE; - -#ifdef WITH_THREAD - -/* Ensure that the current thread is ready to call the Python - C API, regardless of the current state of Python, or of its - thread lock. This may be called as many times as desired - by a thread so long as each call is matched with a call to - PyGILState_Release(). In general, other thread-state APIs may - be used between _Ensure() and _Release() calls, so long as the - thread-state is restored to its previous state before the Release(). - For example, normal use of the Py_BEGIN_ALLOW_THREADS/ - Py_END_ALLOW_THREADS macros are acceptable. - - The return value is an opaque "handle" to the thread state when - PyGILState_Ensure() was called, and must be passed to - PyGILState_Release() to ensure Python is left in the same state. Even - though recursive calls are allowed, these handles can *not* be shared - - each unique call to PyGILState_Ensure must save the handle for its - call to PyGILState_Release. - - When the function returns, the current thread will hold the GIL. - - Failure is a fatal error. -*/ -PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure(void); - -/* Release any resources previously acquired. After this call, Python's - state will be the same as it was prior to the corresponding - PyGILState_Ensure() call (but generally this state will be unknown to - the caller, hence the use of the GILState API.) - - Every call to PyGILState_Ensure must be matched by a call to - PyGILState_Release on the same thread. -*/ -PyAPI_FUNC(void) PyGILState_Release(PyGILState_STATE); - -/* Helper/diagnostic function - get the current thread state for - this thread. May return NULL if no GILState API has been used - on the current thread. Note that the main thread always has such a - thread-state, even if no auto-thread-state call has been made - on the main thread. -*/ -PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void); - -/* Helper/diagnostic function - return 1 if the current thread - * currently holds the GIL, 0 otherwise - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyGILState_Check(void); -#endif - -#endif /* #ifdef WITH_THREAD */ - -/* The implementation of sys._current_frames() Returns a dict mapping - thread id to that thread's current frame. -*/ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void); -#endif - -/* Routines for advanced debuggers, requested by David Beazley. - Don't use unless you know what you are doing! */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Head(void); -PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Next(PyInterpreterState *); -PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *); -PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *); - -typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); -#endif - -/* hook for PyEval_GetFrame(), requested for Psyco */ -#ifndef Py_LIMITED_API -PyAPI_DATA(PyThreadFrameGetter) _PyThreadState_GetFrame; -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYSTATE_H */ + +/* Thread and interpreter state structures and their interfaces */ + + +#ifndef Py_PYSTATE_H +#define Py_PYSTATE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* State shared between threads */ + +struct _ts; /* Forward */ +struct _is; /* Forward */ + +#ifdef Py_LIMITED_API +typedef struct _is PyInterpreterState; +#else +typedef struct _is { + + struct _is *next; + struct _ts *tstate_head; + + PyObject *modules; + PyObject *modules_by_index; + PyObject *sysdict; + PyObject *builtins; + PyObject *importlib; + + PyObject *codec_search_path; + PyObject *codec_search_cache; + PyObject *codec_error_registry; + int codecs_initialized; + int fscodec_initialized; + +#ifdef HAVE_DLOPEN + int dlopenflags; +#endif +#ifdef WITH_TSC + int tscdump; +#endif + + PyObject *builtins_copy; +} PyInterpreterState; +#endif + + +/* State unique per thread */ + +struct _frame; /* Avoid including frameobject.h */ + +#ifndef Py_LIMITED_API +/* Py_tracefunc return -1 when raising an exception, or 0 for success. */ +typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); + +/* The following values are used for 'what' for tracefunc functions: */ +#define PyTrace_CALL 0 +#define PyTrace_EXCEPTION 1 +#define PyTrace_LINE 2 +#define PyTrace_RETURN 3 +#define PyTrace_C_CALL 4 +#define PyTrace_C_EXCEPTION 5 +#define PyTrace_C_RETURN 6 +#endif + +#ifdef Py_LIMITED_API +typedef struct _ts PyThreadState; +#else +typedef struct _ts { + /* See Python/ceval.c for comments explaining most fields */ + + struct _ts *prev; + struct _ts *next; + PyInterpreterState *interp; + + struct _frame *frame; + int recursion_depth; + char overflowed; /* The stack has overflowed. Allow 50 more calls + to handle the runtime error. */ + char recursion_critical; /* The current calls must not cause + a stack overflow. */ + /* 'tracing' keeps track of the execution depth when tracing/profiling. + This is to prevent the actual trace/profile code from being recorded in + the trace/profile. */ + int tracing; + int use_tracing; + + Py_tracefunc c_profilefunc; + Py_tracefunc c_tracefunc; + PyObject *c_profileobj; + PyObject *c_traceobj; + + PyObject *curexc_type; + PyObject *curexc_value; + PyObject *curexc_traceback; + + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; + + PyObject *dict; /* Stores per-thread state */ + + int gilstate_counter; + + PyObject *async_exc; /* Asynchronous exception to raise */ + long thread_id; /* Thread id where this tstate was created */ + + int trash_delete_nesting; + PyObject *trash_delete_later; + + /* Called when a thread state is deleted normally, but not when it + * is destroyed after fork(). + * Pain: to prevent rare but fatal shutdown errors (issue 18808), + * Thread.join() must wait for the join'ed thread's tstate to be unlinked + * from the tstate chain. That happens at the end of a thread's life, + * in pystate.c. + * The obvious way doesn't quite work: create a lock which the tstate + * unlinking code releases, and have Thread.join() wait to acquire that + * lock. The problem is that we _are_ at the end of the thread's life: + * if the thread holds the last reference to the lock, decref'ing the + * lock will delete the lock, and that may trigger arbitrary Python code + * if there's a weakref, with a callback, to the lock. But by this time + * _PyThreadState_Current is already NULL, so only the simplest of C code + * can be allowed to run (in particular it must not be possible to + * release the GIL). + * So instead of holding the lock directly, the tstate holds a weakref to + * the lock: that's the value of on_delete_data below. Decref'ing a + * weakref is harmless. + * on_delete points to _threadmodule.c's static release_sentinel() function. + * After the tstate is unlinked, release_sentinel is called with the + * weakref-to-lock (on_delete_data) argument, and release_sentinel releases + * the indirectly held lock. + */ + void (*on_delete)(void *); + void *on_delete_data; + + PyObject *coroutine_wrapper; + int in_coroutine_wrapper; + + /* XXX signal handlers should also be here */ + +} PyThreadState; +#endif + + +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void); +PyAPI_FUNC(void) PyInterpreterState_Clear(PyInterpreterState *); +PyAPI_FUNC(void) PyInterpreterState_Delete(PyInterpreterState *); +PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +/* New in 3.3 */ +PyAPI_FUNC(int) PyState_AddModule(PyObject*, struct PyModuleDef*); +PyAPI_FUNC(int) PyState_RemoveModule(struct PyModuleDef*); +#endif +PyAPI_FUNC(PyObject*) PyState_FindModule(struct PyModuleDef*); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyState_ClearModules(void); +#endif + +PyAPI_FUNC(PyThreadState *) PyThreadState_New(PyInterpreterState *); +PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); +PyAPI_FUNC(void) _PyThreadState_Init(PyThreadState *); +PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *); +PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); +PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); +#ifdef WITH_THREAD +PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); +PyAPI_FUNC(void) _PyGILState_Reinit(void); +#endif + +/* Return the current thread state. The global interpreter lock must be held. + * When the current thread state is NULL, this issues a fatal error (so that + * the caller needn't check for NULL). */ +PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); + +/* Similar to PyThreadState_Get(), but don't issue a fatal error + * if it is NULL. */ +PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void); + +PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *); +PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void); +PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *); + + +/* Variable and macro for in-line access to current thread state */ + +/* Assuming the current thread holds the GIL, this is the + PyThreadState for the current thread. */ +#if defined(Py_BUILD_CORE) && !defined(__cplusplus) +PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; +# define PyThreadState_GET() \ + ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) +#else +# define PyThreadState_GET() PyThreadState_Get() +#endif + +typedef + enum {PyGILState_LOCKED, PyGILState_UNLOCKED} + PyGILState_STATE; + +#ifdef WITH_THREAD + +/* Ensure that the current thread is ready to call the Python + C API, regardless of the current state of Python, or of its + thread lock. This may be called as many times as desired + by a thread so long as each call is matched with a call to + PyGILState_Release(). In general, other thread-state APIs may + be used between _Ensure() and _Release() calls, so long as the + thread-state is restored to its previous state before the Release(). + For example, normal use of the Py_BEGIN_ALLOW_THREADS/ + Py_END_ALLOW_THREADS macros are acceptable. + + The return value is an opaque "handle" to the thread state when + PyGILState_Ensure() was called, and must be passed to + PyGILState_Release() to ensure Python is left in the same state. Even + though recursive calls are allowed, these handles can *not* be shared - + each unique call to PyGILState_Ensure must save the handle for its + call to PyGILState_Release. + + When the function returns, the current thread will hold the GIL. + + Failure is a fatal error. +*/ +PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure(void); + +/* Release any resources previously acquired. After this call, Python's + state will be the same as it was prior to the corresponding + PyGILState_Ensure() call (but generally this state will be unknown to + the caller, hence the use of the GILState API.) + + Every call to PyGILState_Ensure must be matched by a call to + PyGILState_Release on the same thread. +*/ +PyAPI_FUNC(void) PyGILState_Release(PyGILState_STATE); + +/* Helper/diagnostic function - get the current thread state for + this thread. May return NULL if no GILState API has been used + on the current thread. Note that the main thread always has such a + thread-state, even if no auto-thread-state call has been made + on the main thread. +*/ +PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void); + +/* Helper/diagnostic function - return 1 if the current thread + * currently holds the GIL, 0 otherwise + */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyGILState_Check(void); +#endif + +#endif /* #ifdef WITH_THREAD */ + +/* The implementation of sys._current_frames() Returns a dict mapping + thread id to that thread's current frame. +*/ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void); +#endif + +/* Routines for advanced debuggers, requested by David Beazley. + Don't use unless you know what you are doing! */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Head(void); +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Next(PyInterpreterState *); +PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *); +PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *); + +typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); +#endif + +/* hook for PyEval_GetFrame(), requested for Psyco */ +#ifndef Py_LIMITED_API +PyAPI_DATA(PyThreadFrameGetter) _PyThreadState_GetFrame; +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYSTATE_H */ diff --git a/libs/nxpy/include/pystrcmp.h b/libs/nxpy/include/pystrcmp.h index edb12397..eccabdce 100644 --- a/libs/nxpy/include/pystrcmp.h +++ b/libs/nxpy/include/pystrcmp.h @@ -1,23 +1,23 @@ -#ifndef Py_STRCMP_H -#define Py_STRCMP_H - -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(int) PyOS_mystrnicmp(const char *, const char *, Py_ssize_t); -PyAPI_FUNC(int) PyOS_mystricmp(const char *, const char *); - -#ifdef MS_WINDOWS -#define PyOS_strnicmp strnicmp -#define PyOS_stricmp stricmp -#else -#define PyOS_strnicmp PyOS_mystrnicmp -#define PyOS_stricmp PyOS_mystricmp -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRCMP_H */ +#ifndef Py_STRCMP_H +#define Py_STRCMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(int) PyOS_mystrnicmp(const char *, const char *, Py_ssize_t); +PyAPI_FUNC(int) PyOS_mystricmp(const char *, const char *); + +#ifdef MS_WINDOWS +#define PyOS_strnicmp strnicmp +#define PyOS_stricmp stricmp +#else +#define PyOS_strnicmp PyOS_mystrnicmp +#define PyOS_stricmp PyOS_mystricmp +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_STRCMP_H */ diff --git a/libs/nxpy/include/pystrhex.h b/libs/nxpy/include/pystrhex.h index 1dc12557..e978578e 100644 --- a/libs/nxpy/include/pystrhex.h +++ b/libs/nxpy/include/pystrhex.h @@ -1,17 +1,17 @@ -#ifndef Py_STRHEX_H -#define Py_STRHEX_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Returns a str() containing the hex representation of argbuf. */ -PyAPI_FUNC(PyObject*) _Py_strhex(const char* argbuf, const Py_ssize_t arglen); -/* Returns a bytes() containing the ASCII hex representation of argbuf. */ -PyAPI_FUNC(PyObject*) _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRHEX_H */ +#ifndef Py_STRHEX_H +#define Py_STRHEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns a str() containing the hex representation of argbuf. */ +PyAPI_FUNC(PyObject*) _Py_strhex(const char* argbuf, const Py_ssize_t arglen); +/* Returns a bytes() containing the ASCII hex representation of argbuf. */ +PyAPI_FUNC(PyObject*) _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_STRHEX_H */ diff --git a/libs/nxpy/include/pystrtod.h b/libs/nxpy/include/pystrtod.h index 23fd1c62..b31ca238 100644 --- a/libs/nxpy/include/pystrtod.h +++ b/libs/nxpy/include/pystrtod.h @@ -1,41 +1,41 @@ -#ifndef Py_STRTOD_H -#define Py_STRTOD_H - -#ifdef __cplusplus -extern "C" { -#endif - - -PyAPI_FUNC(double) PyOS_string_to_double(const char *str, - char **endptr, - PyObject *overflow_exception); - -/* The caller is responsible for calling PyMem_Free to free the buffer - that's is returned. */ -PyAPI_FUNC(char *) PyOS_double_to_string(double val, - char format_code, - int precision, - int flags, - int *type); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr); -#endif - - -/* PyOS_double_to_string's "flags" parameter can be set to 0 or more of: */ -#define Py_DTSF_SIGN 0x01 /* always add the sign */ -#define Py_DTSF_ADD_DOT_0 0x02 /* if the result is an integer add ".0" */ -#define Py_DTSF_ALT 0x04 /* "alternate" formatting. it's format_code - specific */ - -/* PyOS_double_to_string's "type", if non-NULL, will be set to one of: */ -#define Py_DTST_FINITE 0 -#define Py_DTST_INFINITE 1 -#define Py_DTST_NAN 2 - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_STRTOD_H */ +#ifndef Py_STRTOD_H +#define Py_STRTOD_H + +#ifdef __cplusplus +extern "C" { +#endif + + +PyAPI_FUNC(double) PyOS_string_to_double(const char *str, + char **endptr, + PyObject *overflow_exception); + +/* The caller is responsible for calling PyMem_Free to free the buffer + that's is returned. */ +PyAPI_FUNC(char *) PyOS_double_to_string(double val, + char format_code, + int precision, + int flags, + int *type); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr); +#endif + + +/* PyOS_double_to_string's "flags" parameter can be set to 0 or more of: */ +#define Py_DTSF_SIGN 0x01 /* always add the sign */ +#define Py_DTSF_ADD_DOT_0 0x02 /* if the result is an integer add ".0" */ +#define Py_DTSF_ALT 0x04 /* "alternate" formatting. it's format_code + specific */ + +/* PyOS_double_to_string's "type", if non-NULL, will be set to one of: */ +#define Py_DTST_FINITE 0 +#define Py_DTST_INFINITE 1 +#define Py_DTST_NAN 2 + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_STRTOD_H */ diff --git a/libs/nxpy/include/pythonrun.h b/libs/nxpy/include/pythonrun.h index 9c2e813a..e31639f7 100644 --- a/libs/nxpy/include/pythonrun.h +++ b/libs/nxpy/include/pythonrun.h @@ -1,195 +1,195 @@ - -/* Interfaces to parse and execute pieces of python code */ - -#ifndef Py_PYTHONRUN_H -#define Py_PYTHONRUN_H -#ifdef __cplusplus -extern "C" { -#endif - -#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ - CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \ - CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \ - CO_FUTURE_GENERATOR_STOP) -#define PyCF_MASK_OBSOLETE (CO_NESTED) -#define PyCF_SOURCE_IS_UTF8 0x0100 -#define PyCF_DONT_IMPLY_DEDENT 0x0200 -#define PyCF_ONLY_AST 0x0400 -#define PyCF_IGNORE_COOKIE 0x0800 - -#ifndef Py_LIMITED_API -typedef struct { - int cf_flags; /* bitmask of CO_xxx flags relevant to future */ -} PyCompilerFlags; -#endif - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); -PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); -PyAPI_FUNC(int) PyRun_AnyFileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int closeit, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_SimpleFileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int closeit, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveOneFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveOneObject( - FILE *fp, - PyObject *filename, - PyCompilerFlags *flags); -PyAPI_FUNC(int) PyRun_InteractiveLoopFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - PyCompilerFlags *flags); - -PyAPI_FUNC(struct _mod *) PyParser_ASTFromString( - const char *s, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromStringObject( - const char *s, - PyObject *filename, - int start, - PyCompilerFlags *flags, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - const char* enc, - int start, - char *ps1, - char *ps2, - PyCompilerFlags *flags, - int *errcode, - PyArena *arena); -PyAPI_FUNC(struct _mod *) PyParser_ASTFromFileObject( - FILE *fp, - PyObject *filename, - const char* enc, - int start, - char *ps1, - char *ps2, - PyCompilerFlags *flags, - int *errcode, - PyArena *arena); -#endif - -#ifndef PyParser_SimpleParseString -#define PyParser_SimpleParseString(S, B) \ - PyParser_SimpleParseStringFlags(S, B, 0) -#define PyParser_SimpleParseFile(FP, S, B) \ - PyParser_SimpleParseFileFlags(FP, S, B, 0) -#endif -PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, - int); -PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlagsFilename(const char *, - const char *, - int, int); -PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *, - int, int); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, - PyObject *, PyCompilerFlags *); - -PyAPI_FUNC(PyObject *) PyRun_FileExFlags( - FILE *fp, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyObject *globals, - PyObject *locals, - int closeit, - PyCompilerFlags *flags); -#endif - -#ifdef Py_LIMITED_API -PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); -#else -#define Py_CompileString(str, p, s) Py_CompileStringExFlags(str, p, s, NULL, -1) -#define Py_CompileStringFlags(str, p, s, f) Py_CompileStringExFlags(str, p, s, f, -1) -PyAPI_FUNC(PyObject *) Py_CompileStringExFlags( - const char *str, - const char *filename, /* decoded from the filesystem encoding */ - int start, - PyCompilerFlags *flags, - int optimize); -PyAPI_FUNC(PyObject *) Py_CompileStringObject( - const char *str, - PyObject *filename, int start, - PyCompilerFlags *flags, - int optimize); -#endif -PyAPI_FUNC(struct symtable *) Py_SymtableString( - const char *str, - const char *filename, /* decoded from the filesystem encoding */ - int start); -#ifndef Py_LIMITED_API -PyAPI_FUNC(struct symtable *) Py_SymtableStringObject( - const char *str, - PyObject *filename, - int start); -#endif - -PyAPI_FUNC(void) PyErr_Print(void); -PyAPI_FUNC(void) PyErr_PrintEx(int); -PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); - -#ifndef Py_LIMITED_API -/* Use macros for a bunch of old variants */ -#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) -#define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL) -#define PyRun_AnyFileEx(fp, name, closeit) \ - PyRun_AnyFileExFlags(fp, name, closeit, NULL) -#define PyRun_AnyFileFlags(fp, name, flags) \ - PyRun_AnyFileExFlags(fp, name, 0, flags) -#define PyRun_SimpleString(s) PyRun_SimpleStringFlags(s, NULL) -#define PyRun_SimpleFile(f, p) PyRun_SimpleFileExFlags(f, p, 0, NULL) -#define PyRun_SimpleFileEx(f, p, c) PyRun_SimpleFileExFlags(f, p, c, NULL) -#define PyRun_InteractiveOne(f, p) PyRun_InteractiveOneFlags(f, p, NULL) -#define PyRun_InteractiveLoop(f, p) PyRun_InteractiveLoopFlags(f, p, NULL) -#define PyRun_File(fp, p, s, g, l) \ - PyRun_FileExFlags(fp, p, s, g, l, 0, NULL) -#define PyRun_FileEx(fp, p, s, g, l, c) \ - PyRun_FileExFlags(fp, p, s, g, l, c, NULL) -#define PyRun_FileFlags(fp, p, s, g, l, flags) \ - PyRun_FileExFlags(fp, p, s, g, l, 0, flags) -#endif - -/* Stuff with no proper home (yet) */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, const char *); -#endif -PyAPI_DATA(int) (*PyOS_InputHook)(void); -PyAPI_DATA(char) *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *); -#ifndef Py_LIMITED_API -PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState; -#endif - -/* Stack size, in "pointers" (so we get extra safety margins - on 64-bit platforms). On a 32-bit platform, this translates - to an 8k margin. */ -#define PYOS_STACK_MARGIN 2048 - -#if defined(WIN32) && !defined(MS_WIN64) && defined(_MSC_VER) && _MSC_VER >= 1300 -/* Enable stack checking under Microsoft C */ -#define USE_STACKCHECK -#endif - -#ifdef USE_STACKCHECK -/* Check that we aren't overflowing our stack */ -PyAPI_FUNC(int) PyOS_CheckStack(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_PYTHONRUN_H */ + +/* Interfaces to parse and execute pieces of python code */ + +#ifndef Py_PYTHONRUN_H +#define Py_PYTHONRUN_H +#ifdef __cplusplus +extern "C" { +#endif + +#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ + CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | \ + CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL | \ + CO_FUTURE_GENERATOR_STOP) +#define PyCF_MASK_OBSOLETE (CO_NESTED) +#define PyCF_SOURCE_IS_UTF8 0x0100 +#define PyCF_DONT_IMPLY_DEDENT 0x0200 +#define PyCF_ONLY_AST 0x0400 +#define PyCF_IGNORE_COOKIE 0x0800 + +#ifndef Py_LIMITED_API +typedef struct { + int cf_flags; /* bitmask of CO_xxx flags relevant to future */ +} PyCompilerFlags; +#endif + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_AnyFileExFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + int closeit, + PyCompilerFlags *flags); +PyAPI_FUNC(int) PyRun_SimpleFileExFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + int closeit, + PyCompilerFlags *flags); +PyAPI_FUNC(int) PyRun_InteractiveOneFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + PyCompilerFlags *flags); +PyAPI_FUNC(int) PyRun_InteractiveOneObject( + FILE *fp, + PyObject *filename, + PyCompilerFlags *flags); +PyAPI_FUNC(int) PyRun_InteractiveLoopFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + PyCompilerFlags *flags); + +PyAPI_FUNC(struct _mod *) PyParser_ASTFromString( + const char *s, + const char *filename, /* decoded from the filesystem encoding */ + int start, + PyCompilerFlags *flags, + PyArena *arena); +PyAPI_FUNC(struct _mod *) PyParser_ASTFromStringObject( + const char *s, + PyObject *filename, + int start, + PyCompilerFlags *flags, + PyArena *arena); +PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + const char* enc, + int start, + char *ps1, + char *ps2, + PyCompilerFlags *flags, + int *errcode, + PyArena *arena); +PyAPI_FUNC(struct _mod *) PyParser_ASTFromFileObject( + FILE *fp, + PyObject *filename, + const char* enc, + int start, + char *ps1, + char *ps2, + PyCompilerFlags *flags, + int *errcode, + PyArena *arena); +#endif + +#ifndef PyParser_SimpleParseString +#define PyParser_SimpleParseString(S, B) \ + PyParser_SimpleParseStringFlags(S, B, 0) +#define PyParser_SimpleParseFile(FP, S, B) \ + PyParser_SimpleParseFileFlags(FP, S, B, 0) +#endif +PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, + int); +PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlagsFilename(const char *, + const char *, + int, int); +PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *, + int, int); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, + PyObject *, PyCompilerFlags *); + +PyAPI_FUNC(PyObject *) PyRun_FileExFlags( + FILE *fp, + const char *filename, /* decoded from the filesystem encoding */ + int start, + PyObject *globals, + PyObject *locals, + int closeit, + PyCompilerFlags *flags); +#endif + +#ifdef Py_LIMITED_API +PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); +#else +#define Py_CompileString(str, p, s) Py_CompileStringExFlags(str, p, s, NULL, -1) +#define Py_CompileStringFlags(str, p, s, f) Py_CompileStringExFlags(str, p, s, f, -1) +PyAPI_FUNC(PyObject *) Py_CompileStringExFlags( + const char *str, + const char *filename, /* decoded from the filesystem encoding */ + int start, + PyCompilerFlags *flags, + int optimize); +PyAPI_FUNC(PyObject *) Py_CompileStringObject( + const char *str, + PyObject *filename, int start, + PyCompilerFlags *flags, + int optimize); +#endif +PyAPI_FUNC(struct symtable *) Py_SymtableString( + const char *str, + const char *filename, /* decoded from the filesystem encoding */ + int start); +#ifndef Py_LIMITED_API +PyAPI_FUNC(struct symtable *) Py_SymtableStringObject( + const char *str, + PyObject *filename, + int start); +#endif + +PyAPI_FUNC(void) PyErr_Print(void); +PyAPI_FUNC(void) PyErr_PrintEx(int); +PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); + +#ifndef Py_LIMITED_API +/* Use macros for a bunch of old variants */ +#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) +#define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL) +#define PyRun_AnyFileEx(fp, name, closeit) \ + PyRun_AnyFileExFlags(fp, name, closeit, NULL) +#define PyRun_AnyFileFlags(fp, name, flags) \ + PyRun_AnyFileExFlags(fp, name, 0, flags) +#define PyRun_SimpleString(s) PyRun_SimpleStringFlags(s, NULL) +#define PyRun_SimpleFile(f, p) PyRun_SimpleFileExFlags(f, p, 0, NULL) +#define PyRun_SimpleFileEx(f, p, c) PyRun_SimpleFileExFlags(f, p, c, NULL) +#define PyRun_InteractiveOne(f, p) PyRun_InteractiveOneFlags(f, p, NULL) +#define PyRun_InteractiveLoop(f, p) PyRun_InteractiveLoopFlags(f, p, NULL) +#define PyRun_File(fp, p, s, g, l) \ + PyRun_FileExFlags(fp, p, s, g, l, 0, NULL) +#define PyRun_FileEx(fp, p, s, g, l, c) \ + PyRun_FileExFlags(fp, p, s, g, l, c, NULL) +#define PyRun_FileFlags(fp, p, s, g, l, flags) \ + PyRun_FileExFlags(fp, p, s, g, l, 0, flags) +#endif + +/* Stuff with no proper home (yet) */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, const char *); +#endif +PyAPI_DATA(int) (*PyOS_InputHook)(void); +PyAPI_DATA(char) *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *); +#ifndef Py_LIMITED_API +PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState; +#endif + +/* Stack size, in "pointers" (so we get extra safety margins + on 64-bit platforms). On a 32-bit platform, this translates + to an 8k margin. */ +#define PYOS_STACK_MARGIN 2048 + +#if defined(WIN32) && !defined(MS_WIN64) && defined(_MSC_VER) && _MSC_VER >= 1300 +/* Enable stack checking under Microsoft C */ +#define USE_STACKCHECK +#endif + +#ifdef USE_STACKCHECK +/* Check that we aren't overflowing our stack */ +PyAPI_FUNC(int) PyOS_CheckStack(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYTHONRUN_H */ diff --git a/libs/nxpy/include/pythread.h b/libs/nxpy/include/pythread.h index 6e9f3033..deef772e 100644 --- a/libs/nxpy/include/pythread.h +++ b/libs/nxpy/include/pythread.h @@ -1,93 +1,93 @@ - -#ifndef Py_PYTHREAD_H -#define Py_PYTHREAD_H - -typedef void *PyThread_type_lock; -typedef void *PyThread_type_sema; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Return status codes for Python lock acquisition. Chosen for maximum - * backwards compatibility, ie failure -> 0, success -> 1. */ -typedef enum PyLockStatus { - PY_LOCK_FAILURE = 0, - PY_LOCK_ACQUIRED = 1, - PY_LOCK_INTR -} PyLockStatus; - -PyAPI_FUNC(void) PyThread_init_thread(void); -PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *); -PyAPI_FUNC(void) PyThread_exit_thread(void); -PyAPI_FUNC(long) PyThread_get_thread_ident(void); - -PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void); -PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock); -PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int); -#define WAIT_LOCK 1 -#define NOWAIT_LOCK 0 - -/* PY_TIMEOUT_T is the integral type used to specify timeouts when waiting - on a lock (see PyThread_acquire_lock_timed() below). - PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that - type, and depends on the system threading API. - - NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread - module exposes a higher-level API, with timeouts expressed in seconds - and floating-point numbers allowed. -*/ -#if defined(HAVE_LONG_LONG) -#define PY_TIMEOUT_T PY_LONG_LONG -#define PY_TIMEOUT_MAX PY_LLONG_MAX -#else -#define PY_TIMEOUT_T long -#define PY_TIMEOUT_MAX LONG_MAX -#endif - -/* In the NT API, the timeout is a DWORD and is expressed in milliseconds */ -#if defined (NT_THREADS) -#if (Py_LL(0xFFFFFFFF) * 1000 < PY_TIMEOUT_MAX) -#undef PY_TIMEOUT_MAX -#define PY_TIMEOUT_MAX (Py_LL(0xFFFFFFFF) * 1000) -#endif -#endif - -/* If microseconds == 0, the call is non-blocking: it returns immediately - even when the lock can't be acquired. - If microseconds > 0, the call waits up to the specified duration. - If microseconds < 0, the call waits until success (or abnormal failure) - - microseconds must be less than PY_TIMEOUT_MAX. Behaviour otherwise is - undefined. - - If intr_flag is true and the acquire is interrupted by a signal, then the - call will return PY_LOCK_INTR. The caller may reattempt to acquire the - lock. -*/ -PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed(PyThread_type_lock, - PY_TIMEOUT_T microseconds, - int intr_flag); - -PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock); - -PyAPI_FUNC(size_t) PyThread_get_stacksize(void); -PyAPI_FUNC(int) PyThread_set_stacksize(size_t); - -PyAPI_FUNC(PyObject*) PyThread_GetInfo(void); - -/* Thread Local Storage (TLS) API */ -PyAPI_FUNC(int) PyThread_create_key(void); -PyAPI_FUNC(void) PyThread_delete_key(int); -PyAPI_FUNC(int) PyThread_set_key_value(int, void *); -PyAPI_FUNC(void *) PyThread_get_key_value(int); -PyAPI_FUNC(void) PyThread_delete_key_value(int key); - -/* Cleanup after a fork */ -PyAPI_FUNC(void) PyThread_ReInitTLS(void); - -#ifdef __cplusplus -} -#endif - -#endif /* !Py_PYTHREAD_H */ + +#ifndef Py_PYTHREAD_H +#define Py_PYTHREAD_H + +typedef void *PyThread_type_lock; +typedef void *PyThread_type_sema; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return status codes for Python lock acquisition. Chosen for maximum + * backwards compatibility, ie failure -> 0, success -> 1. */ +typedef enum PyLockStatus { + PY_LOCK_FAILURE = 0, + PY_LOCK_ACQUIRED = 1, + PY_LOCK_INTR +} PyLockStatus; + +PyAPI_FUNC(void) PyThread_init_thread(void); +PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *); +PyAPI_FUNC(void) PyThread_exit_thread(void); +PyAPI_FUNC(long) PyThread_get_thread_ident(void); + +PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void); +PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock); +PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int); +#define WAIT_LOCK 1 +#define NOWAIT_LOCK 0 + +/* PY_TIMEOUT_T is the integral type used to specify timeouts when waiting + on a lock (see PyThread_acquire_lock_timed() below). + PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that + type, and depends on the system threading API. + + NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread + module exposes a higher-level API, with timeouts expressed in seconds + and floating-point numbers allowed. +*/ +#if defined(HAVE_LONG_LONG) +#define PY_TIMEOUT_T PY_LONG_LONG +#define PY_TIMEOUT_MAX PY_LLONG_MAX +#else +#define PY_TIMEOUT_T long +#define PY_TIMEOUT_MAX LONG_MAX +#endif + +/* In the NT API, the timeout is a DWORD and is expressed in milliseconds */ +#if defined (NT_THREADS) +#if (Py_LL(0xFFFFFFFF) * 1000 < PY_TIMEOUT_MAX) +#undef PY_TIMEOUT_MAX +#define PY_TIMEOUT_MAX (Py_LL(0xFFFFFFFF) * 1000) +#endif +#endif + +/* If microseconds == 0, the call is non-blocking: it returns immediately + even when the lock can't be acquired. + If microseconds > 0, the call waits up to the specified duration. + If microseconds < 0, the call waits until success (or abnormal failure) + + microseconds must be less than PY_TIMEOUT_MAX. Behaviour otherwise is + undefined. + + If intr_flag is true and the acquire is interrupted by a signal, then the + call will return PY_LOCK_INTR. The caller may reattempt to acquire the + lock. +*/ +PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed(PyThread_type_lock, + PY_TIMEOUT_T microseconds, + int intr_flag); + +PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock); + +PyAPI_FUNC(size_t) PyThread_get_stacksize(void); +PyAPI_FUNC(int) PyThread_set_stacksize(size_t); + +PyAPI_FUNC(PyObject*) PyThread_GetInfo(void); + +/* Thread Local Storage (TLS) API */ +PyAPI_FUNC(int) PyThread_create_key(void); +PyAPI_FUNC(void) PyThread_delete_key(int); +PyAPI_FUNC(int) PyThread_set_key_value(int, void *); +PyAPI_FUNC(void *) PyThread_get_key_value(int); +PyAPI_FUNC(void) PyThread_delete_key_value(int key); + +/* Cleanup after a fork */ +PyAPI_FUNC(void) PyThread_ReInitTLS(void); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYTHREAD_H */ diff --git a/libs/nxpy/include/pytime.h b/libs/nxpy/include/pytime.h index 494322c5..b5cbb7c9 100644 --- a/libs/nxpy/include/pytime.h +++ b/libs/nxpy/include/pytime.h @@ -1,193 +1,193 @@ -#ifndef Py_LIMITED_API -#ifndef Py_PYTIME_H -#define Py_PYTIME_H - -#include "pyconfig.h" /* include for defines */ -#include "object.h" - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to time related -functions and constants -**************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef PY_INT64_T -/* _PyTime_t: Python timestamp with subsecond precision. It can be used to - store a duration, and so indirectly a date (related to another date, like - UNIX epoch). */ -typedef PY_INT64_T _PyTime_t; -#define _PyTime_MIN PY_LLONG_MIN -#define _PyTime_MAX PY_LLONG_MAX -#else -# error "_PyTime_t need signed 64-bit integer type" -#endif - -typedef enum { - /* Round towards minus infinity (-inf). - For example, used to read a clock. */ - _PyTime_ROUND_FLOOR=0, - /* Round towards infinity (+inf). - For example, used for timeout to wait "at least" N seconds. */ - _PyTime_ROUND_CEILING -} _PyTime_round_t; - -/* Convert a time_t to a PyLong. */ -PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( - time_t sec); - -/* Convert a PyLong to a time_t. */ -PyAPI_FUNC(time_t) _PyLong_AsTime_t( - PyObject *obj); - -/* Convert a number of seconds, int or float, to time_t. */ -PyAPI_FUNC(int) _PyTime_ObjectToTime_t( - PyObject *obj, - time_t *sec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timeval structure. - usec is in the range [0; 999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimeval( - PyObject *obj, - time_t *sec, - long *usec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timespec structure. - nsec is in the range [0; 999999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimespec( - PyObject *obj, - time_t *sec, - long *nsec, - _PyTime_round_t); - - -/* Create a timestamp from a number of seconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); - -/* Macro to create a timestamp from a number of seconds, no integer overflow. - Only use the macro for small values, prefer _PyTime_FromSeconds(). */ -#define _PYTIME_FROMSECONDS(seconds) \ - ((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) - -/* Create a timestamp from a number of nanoseconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(PY_LONG_LONG ns); - -/* Convert a number of seconds (Python float or int) to a timetamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromSecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a number of milliseconds (Python float or int, 10^-3) to a timetamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromMillisecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds as a C double. */ -PyAPI_FUNC(double) _PyTime_AsSecondsDouble(_PyTime_t t); - -/* Convert timestamp to a number of milliseconds (10^-3 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of microseconds (10^-6 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int - object. */ -PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); - -/* Convert a timestamp to a timeval structure (microsecond resolution). - tv_usec is always positive. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Similar to _PyTime_AsTimeval(), but don't raise an exception on error. */ -PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds (secs) and microseconds (us). - us is always positive. This function is similar to _PyTime_AsTimeval() - except that secs is always a time_t type, whereas the timeval structure - uses a C long for tv_sec on Windows. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( - _PyTime_t t, - time_t *secs, - int *us, - _PyTime_round_t round); - -#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) -/* Convert a timestamp to a timespec structure (nanosecond resolution). - tv_nsec is always positive. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); -#endif - -/* Get the current time from the system clock. - - The function cannot fail. _PyTime_Init() ensures that the system clock - works. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - The function cannot fail. _PyTime_Init() ensures that a monotonic clock - is available and works. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void); - - -/* Structure used by time.get_clock_info() */ -typedef struct { - const char *implementation; - int monotonic; - int adjustable; - double resolution; -} _Py_clock_info_t; - -/* Get the current time from the system clock. - * Fill clock information if info is not NULL. - * Raise an exception and return -1 on error, return 0 on success. - */ -PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - Fill info (if set) with information of the function used to get the time. - - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - - -/* Initialize time. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_Init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* Py_PYTIME_H */ -#endif /* Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_PYTIME_H +#define Py_PYTIME_H + +#include "pyconfig.h" /* include for defines */ +#include "object.h" + +/************************************************************************** +Symbols and macros to supply platform-independent interfaces to time related +functions and constants +**************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PY_INT64_T +/* _PyTime_t: Python timestamp with subsecond precision. It can be used to + store a duration, and so indirectly a date (related to another date, like + UNIX epoch). */ +typedef PY_INT64_T _PyTime_t; +#define _PyTime_MIN PY_LLONG_MIN +#define _PyTime_MAX PY_LLONG_MAX +#else +# error "_PyTime_t need signed 64-bit integer type" +#endif + +typedef enum { + /* Round towards minus infinity (-inf). + For example, used to read a clock. */ + _PyTime_ROUND_FLOOR=0, + /* Round towards infinity (+inf). + For example, used for timeout to wait "at least" N seconds. */ + _PyTime_ROUND_CEILING +} _PyTime_round_t; + +/* Convert a time_t to a PyLong. */ +PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( + time_t sec); + +/* Convert a PyLong to a time_t. */ +PyAPI_FUNC(time_t) _PyLong_AsTime_t( + PyObject *obj); + +/* Convert a number of seconds, int or float, to time_t. */ +PyAPI_FUNC(int) _PyTime_ObjectToTime_t( + PyObject *obj, + time_t *sec, + _PyTime_round_t); + +/* Convert a number of seconds, int or float, to a timeval structure. + usec is in the range [0; 999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimeval( + PyObject *obj, + time_t *sec, + long *usec, + _PyTime_round_t); + +/* Convert a number of seconds, int or float, to a timespec structure. + nsec is in the range [0; 999999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimespec( + PyObject *obj, + time_t *sec, + long *nsec, + _PyTime_round_t); + + +/* Create a timestamp from a number of seconds. */ +PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); + +/* Macro to create a timestamp from a number of seconds, no integer overflow. + Only use the macro for small values, prefer _PyTime_FromSeconds(). */ +#define _PYTIME_FROMSECONDS(seconds) \ + ((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) + +/* Create a timestamp from a number of nanoseconds. */ +PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(PY_LONG_LONG ns); + +/* Convert a number of seconds (Python float or int) to a timetamp. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_FromSecondsObject(_PyTime_t *t, + PyObject *obj, + _PyTime_round_t round); + +/* Convert a number of milliseconds (Python float or int, 10^-3) to a timetamp. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_FromMillisecondsObject(_PyTime_t *t, + PyObject *obj, + _PyTime_round_t round); + +/* Convert a timestamp to a number of seconds as a C double. */ +PyAPI_FUNC(double) _PyTime_AsSecondsDouble(_PyTime_t t); + +/* Convert timestamp to a number of milliseconds (10^-3 seconds). */ +PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t, + _PyTime_round_t round); + +/* Convert timestamp to a number of microseconds (10^-6 seconds). */ +PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, + _PyTime_round_t round); + +/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int + object. */ +PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); + +/* Convert a timestamp to a timeval structure (microsecond resolution). + tv_usec is always positive. + Raise an exception and return -1 if the conversion overflowed, + return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, + struct timeval *tv, + _PyTime_round_t round); + +/* Similar to _PyTime_AsTimeval(), but don't raise an exception on error. */ +PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t, + struct timeval *tv, + _PyTime_round_t round); + +/* Convert a timestamp to a number of seconds (secs) and microseconds (us). + us is always positive. This function is similar to _PyTime_AsTimeval() + except that secs is always a time_t type, whereas the timeval structure + uses a C long for tv_sec on Windows. + Raise an exception and return -1 if the conversion overflowed, + return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( + _PyTime_t t, + time_t *secs, + int *us, + _PyTime_round_t round); + +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) +/* Convert a timestamp to a timespec structure (nanosecond resolution). + tv_nsec is always positive. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); +#endif + +/* Get the current time from the system clock. + + The function cannot fail. _PyTime_Init() ensures that the system clock + works. */ +PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void); + +/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. + The clock is not affected by system clock updates. The reference point of + the returned value is undefined, so that only the difference between the + results of consecutive calls is valid. + + The function cannot fail. _PyTime_Init() ensures that a monotonic clock + is available and works. */ +PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void); + + +/* Structure used by time.get_clock_info() */ +typedef struct { + const char *implementation; + int monotonic; + int adjustable; + double resolution; +} _Py_clock_info_t; + +/* Get the current time from the system clock. + * Fill clock information if info is not NULL. + * Raise an exception and return -1 on error, return 0 on success. + */ +PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); + +/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. + The clock is not affected by system clock updates. The reference point of + the returned value is undefined, so that only the difference between the + results of consecutive calls is valid. + + Fill info (if set) with information of the function used to get the time. + + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); + + +/* Initialize time. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_Init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* Py_PYTIME_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/rangeobject.h b/libs/nxpy/include/rangeobject.h index 7e4dc288..b9a136d0 100644 --- a/libs/nxpy/include/rangeobject.h +++ b/libs/nxpy/include/rangeobject.h @@ -1,27 +1,27 @@ - -/* Range object interface */ - -#ifndef Py_RANGEOBJECT_H -#define Py_RANGEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* -A range object represents an integer range. This is an immutable object; -a range cannot change its value after creation. - -Range objects behave like the corresponding tuple objects except that -they are represented by a start, stop, and step datamembers. -*/ - -PyAPI_DATA(PyTypeObject) PyRange_Type; -PyAPI_DATA(PyTypeObject) PyRangeIter_Type; -PyAPI_DATA(PyTypeObject) PyLongRangeIter_Type; - -#define PyRange_Check(op) (Py_TYPE(op) == &PyRange_Type) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_RANGEOBJECT_H */ + +/* Range object interface */ + +#ifndef Py_RANGEOBJECT_H +#define Py_RANGEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* +A range object represents an integer range. This is an immutable object; +a range cannot change its value after creation. + +Range objects behave like the corresponding tuple objects except that +they are represented by a start, stop, and step datamembers. +*/ + +PyAPI_DATA(PyTypeObject) PyRange_Type; +PyAPI_DATA(PyTypeObject) PyRangeIter_Type; +PyAPI_DATA(PyTypeObject) PyLongRangeIter_Type; + +#define PyRange_Check(op) (Py_TYPE(op) == &PyRange_Type) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_RANGEOBJECT_H */ diff --git a/libs/nxpy/include/setobject.h b/libs/nxpy/include/setobject.h index f17bc1b0..b227e26b 100644 --- a/libs/nxpy/include/setobject.h +++ b/libs/nxpy/include/setobject.h @@ -1,107 +1,107 @@ -/* Set object interface */ - -#ifndef Py_SETOBJECT_H -#define Py_SETOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API - -/* There are three kinds of entries in the table: - -1. Unused: key == NULL -2. Active: key != NULL and key != dummy -3. Dummy: key == dummy - -The hash field of Unused slots have no meaning. -The hash field of Dummny slots are set to -1 -meaning that dummy entries can be detected by -either entry->key==dummy or by entry->hash==-1. -*/ - -#define PySet_MINSIZE 8 - -typedef struct { - PyObject *key; - Py_hash_t hash; /* Cached hash code of the key */ -} setentry; - -/* The SetObject data structure is shared by set and frozenset objects. - -Invariant for sets: - - hash is -1 - -Invariants for frozensets: - - data is immutable. - - hash is the hash of the frozenset or -1 if not computed yet. - -*/ - -typedef struct { - PyObject_HEAD - - Py_ssize_t fill; /* Number active and dummy entries*/ - Py_ssize_t used; /* Number active entries */ - - /* The table contains mask + 1 slots, and that's a power of 2. - * We store the mask instead of the size because the mask is more - * frequently needed. - */ - Py_ssize_t mask; - - /* The table points to a fixed-size smalltable for small tables - * or to additional malloc'ed memory for bigger tables. - * The table pointer is never NULL which saves us from repeated - * runtime null-tests. - */ - setentry *table; - Py_hash_t hash; /* Only used by frozenset objects */ - Py_ssize_t finger; /* Search finger for pop() */ - - setentry smalltable[PySet_MINSIZE]; - PyObject *weakreflist; /* List of weak references */ -} PySetObject; - -#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used) - -PyAPI_DATA(PyObject *) _PySet_Dummy; - -PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash); -PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); -PyAPI_FUNC(int) PySet_ClearFreeList(void); - -#endif /* Section excluded by Py_LIMITED_API */ - -PyAPI_DATA(PyTypeObject) PySet_Type; -PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; -PyAPI_DATA(PyTypeObject) PySetIter_Type; - -PyAPI_FUNC(PyObject *) PySet_New(PyObject *); -PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); - -PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); -PyAPI_FUNC(int) PySet_Clear(PyObject *set); -PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); -PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); -PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); -PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset); - -#define PyFrozenSet_CheckExact(ob) (Py_TYPE(ob) == &PyFrozenSet_Type) -#define PyAnySet_CheckExact(ob) \ - (Py_TYPE(ob) == &PySet_Type || Py_TYPE(ob) == &PyFrozenSet_Type) -#define PyAnySet_Check(ob) \ - (Py_TYPE(ob) == &PySet_Type || Py_TYPE(ob) == &PyFrozenSet_Type || \ - PyType_IsSubtype(Py_TYPE(ob), &PySet_Type) || \ - PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) -#define PySet_Check(ob) \ - (Py_TYPE(ob) == &PySet_Type || \ - PyType_IsSubtype(Py_TYPE(ob), &PySet_Type)) -#define PyFrozenSet_Check(ob) \ - (Py_TYPE(ob) == &PyFrozenSet_Type || \ - PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SETOBJECT_H */ +/* Set object interface */ + +#ifndef Py_SETOBJECT_H +#define Py_SETOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API + +/* There are three kinds of entries in the table: + +1. Unused: key == NULL +2. Active: key != NULL and key != dummy +3. Dummy: key == dummy + +The hash field of Unused slots have no meaning. +The hash field of Dummny slots are set to -1 +meaning that dummy entries can be detected by +either entry->key==dummy or by entry->hash==-1. +*/ + +#define PySet_MINSIZE 8 + +typedef struct { + PyObject *key; + Py_hash_t hash; /* Cached hash code of the key */ +} setentry; + +/* The SetObject data structure is shared by set and frozenset objects. + +Invariant for sets: + - hash is -1 + +Invariants for frozensets: + - data is immutable. + - hash is the hash of the frozenset or -1 if not computed yet. + +*/ + +typedef struct { + PyObject_HEAD + + Py_ssize_t fill; /* Number active and dummy entries*/ + Py_ssize_t used; /* Number active entries */ + + /* The table contains mask + 1 slots, and that's a power of 2. + * We store the mask instead of the size because the mask is more + * frequently needed. + */ + Py_ssize_t mask; + + /* The table points to a fixed-size smalltable for small tables + * or to additional malloc'ed memory for bigger tables. + * The table pointer is never NULL which saves us from repeated + * runtime null-tests. + */ + setentry *table; + Py_hash_t hash; /* Only used by frozenset objects */ + Py_ssize_t finger; /* Search finger for pop() */ + + setentry smalltable[PySet_MINSIZE]; + PyObject *weakreflist; /* List of weak references */ +} PySetObject; + +#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used) + +PyAPI_DATA(PyObject *) _PySet_Dummy; + +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash); +PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); +PyAPI_FUNC(int) PySet_ClearFreeList(void); + +#endif /* Section excluded by Py_LIMITED_API */ + +PyAPI_DATA(PyTypeObject) PySet_Type; +PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; +PyAPI_DATA(PyTypeObject) PySetIter_Type; + +PyAPI_FUNC(PyObject *) PySet_New(PyObject *); +PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); + +PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); +PyAPI_FUNC(int) PySet_Clear(PyObject *set); +PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); +PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); +PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); +PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset); + +#define PyFrozenSet_CheckExact(ob) (Py_TYPE(ob) == &PyFrozenSet_Type) +#define PyAnySet_CheckExact(ob) \ + (Py_TYPE(ob) == &PySet_Type || Py_TYPE(ob) == &PyFrozenSet_Type) +#define PyAnySet_Check(ob) \ + (Py_TYPE(ob) == &PySet_Type || Py_TYPE(ob) == &PyFrozenSet_Type || \ + PyType_IsSubtype(Py_TYPE(ob), &PySet_Type) || \ + PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) +#define PySet_Check(ob) \ + (Py_TYPE(ob) == &PySet_Type || \ + PyType_IsSubtype(Py_TYPE(ob), &PySet_Type)) +#define PyFrozenSet_Check(ob) \ + (Py_TYPE(ob) == &PyFrozenSet_Type || \ + PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SETOBJECT_H */ diff --git a/libs/nxpy/include/sliceobject.h b/libs/nxpy/include/sliceobject.h index 26370e01..21d67604 100644 --- a/libs/nxpy/include/sliceobject.h +++ b/libs/nxpy/include/sliceobject.h @@ -1,50 +1,50 @@ -#ifndef Py_SLICEOBJECT_H -#define Py_SLICEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* The unique ellipsis object "..." */ - -PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ - -#define Py_Ellipsis (&_Py_EllipsisObject) - -/* Slice object interface */ - -/* - -A slice object containing start, stop, and step data members (the -names are from range). After much talk with Guido, it was decided to -let these be any arbitrary python type. Py_None stands for omitted values. -*/ -#ifndef Py_LIMITED_API -typedef struct { - PyObject_HEAD - PyObject *start, *stop, *step; /* not NULL */ -} PySliceObject; -#endif - -PyAPI_DATA(PyTypeObject) PySlice_Type; -PyAPI_DATA(PyTypeObject) PyEllipsis_Type; - -#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type) - -PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, - PyObject* step); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); -PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, - PyObject **start_ptr, PyObject **stop_ptr, - PyObject **step_ptr); -#endif -PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); -PyAPI_FUNC(int) PySlice_GetIndicesEx(PyObject *r, Py_ssize_t length, - Py_ssize_t *start, Py_ssize_t *stop, - Py_ssize_t *step, Py_ssize_t *slicelength); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SLICEOBJECT_H */ +#ifndef Py_SLICEOBJECT_H +#define Py_SLICEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* The unique ellipsis object "..." */ + +PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ + +#define Py_Ellipsis (&_Py_EllipsisObject) + +/* Slice object interface */ + +/* + +A slice object containing start, stop, and step data members (the +names are from range). After much talk with Guido, it was decided to +let these be any arbitrary python type. Py_None stands for omitted values. +*/ +#ifndef Py_LIMITED_API +typedef struct { + PyObject_HEAD + PyObject *start, *stop, *step; /* not NULL */ +} PySliceObject; +#endif + +PyAPI_DATA(PyTypeObject) PySlice_Type; +PyAPI_DATA(PyTypeObject) PyEllipsis_Type; + +#define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type) + +PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, + PyObject* step); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); +PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, + PyObject **start_ptr, PyObject **stop_ptr, + PyObject **step_ptr); +#endif +PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); +PyAPI_FUNC(int) PySlice_GetIndicesEx(PyObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, + Py_ssize_t *step, Py_ssize_t *slicelength); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SLICEOBJECT_H */ diff --git a/libs/nxpy/include/structmember.h b/libs/nxpy/include/structmember.h index 948f6903..ca363082 100644 --- a/libs/nxpy/include/structmember.h +++ b/libs/nxpy/include/structmember.h @@ -1,76 +1,76 @@ -#ifndef Py_STRUCTMEMBER_H -#define Py_STRUCTMEMBER_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Interface to map C struct members to Python object attributes */ - -#include /* For offsetof */ - -/* An array of PyMemberDef structures defines the name, type and offset - of selected members of a C structure. These can be read by - PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY - flag is set). The array must be terminated with an entry whose name - pointer is NULL. */ - -typedef struct PyMemberDef { - char *name; - int type; - Py_ssize_t offset; - int flags; - char *doc; -} PyMemberDef; - -/* Types */ -#define T_SHORT 0 -#define T_INT 1 -#define T_LONG 2 -#define T_FLOAT 3 -#define T_DOUBLE 4 -#define T_STRING 5 -#define T_OBJECT 6 -/* XXX the ordering here is weird for binary compatibility */ -#define T_CHAR 7 /* 1-character string */ -#define T_BYTE 8 /* 8-bit signed int */ -/* unsigned variants: */ -#define T_UBYTE 9 -#define T_USHORT 10 -#define T_UINT 11 -#define T_ULONG 12 - -/* Added by Jack: strings contained in the structure */ -#define T_STRING_INPLACE 13 - -/* Added by Lillo: bools contained in the structure (assumed char) */ -#define T_BOOL 14 - -#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError - when the value is NULL, instead of - converting to None. */ -#ifdef HAVE_LONG_LONG -#define T_LONGLONG 17 -#define T_ULONGLONG 18 -#endif /* HAVE_LONG_LONG */ - -#define T_PYSSIZET 19 /* Py_ssize_t */ -#define T_NONE 20 /* Value is always None */ - - -/* Flags */ -#define READONLY 1 -#define READ_RESTRICTED 2 -#define PY_WRITE_RESTRICTED 4 -#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED) - - -/* Current API, use this */ -PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *); -PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_STRUCTMEMBER_H */ +#ifndef Py_STRUCTMEMBER_H +#define Py_STRUCTMEMBER_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Interface to map C struct members to Python object attributes */ + +#include /* For offsetof */ + +/* An array of PyMemberDef structures defines the name, type and offset + of selected members of a C structure. These can be read by + PyMember_GetOne() and set by PyMember_SetOne() (except if their READONLY + flag is set). The array must be terminated with an entry whose name + pointer is NULL. */ + +typedef struct PyMemberDef { + char *name; + int type; + Py_ssize_t offset; + int flags; + char *doc; +} PyMemberDef; + +/* Types */ +#define T_SHORT 0 +#define T_INT 1 +#define T_LONG 2 +#define T_FLOAT 3 +#define T_DOUBLE 4 +#define T_STRING 5 +#define T_OBJECT 6 +/* XXX the ordering here is weird for binary compatibility */ +#define T_CHAR 7 /* 1-character string */ +#define T_BYTE 8 /* 8-bit signed int */ +/* unsigned variants: */ +#define T_UBYTE 9 +#define T_USHORT 10 +#define T_UINT 11 +#define T_ULONG 12 + +/* Added by Jack: strings contained in the structure */ +#define T_STRING_INPLACE 13 + +/* Added by Lillo: bools contained in the structure (assumed char) */ +#define T_BOOL 14 + +#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError + when the value is NULL, instead of + converting to None. */ +#ifdef HAVE_LONG_LONG +#define T_LONGLONG 17 +#define T_ULONGLONG 18 +#endif /* HAVE_LONG_LONG */ + +#define T_PYSSIZET 19 /* Py_ssize_t */ +#define T_NONE 20 /* Value is always None */ + + +/* Flags */ +#define READONLY 1 +#define READ_RESTRICTED 2 +#define PY_WRITE_RESTRICTED 4 +#define RESTRICTED (READ_RESTRICTED | PY_WRITE_RESTRICTED) + + +/* Current API, use this */ +PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *); +PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_STRUCTMEMBER_H */ diff --git a/libs/nxpy/include/structseq.h b/libs/nxpy/include/structseq.h index af227164..f8a3cfc6 100644 --- a/libs/nxpy/include/structseq.h +++ b/libs/nxpy/include/structseq.h @@ -1,49 +1,49 @@ - -/* Named tuple object interface */ - -#ifndef Py_STRUCTSEQ_H -#define Py_STRUCTSEQ_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PyStructSequence_Field { - char *name; - char *doc; -} PyStructSequence_Field; - -typedef struct PyStructSequence_Desc { - char *name; - char *doc; - struct PyStructSequence_Field *fields; - int n_in_sequence; -} PyStructSequence_Desc; - -extern char* PyStructSequence_UnnamedField; - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, - PyStructSequence_Desc *desc); -PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, - PyStructSequence_Desc *desc); -#endif -PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); - -PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); - -#ifndef Py_LIMITED_API -typedef PyTupleObject PyStructSequence; - -/* Macro, *only* to be used to fill in brand new objects */ -#define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM(op, i, v) - -#define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM(op, i) -#endif - -PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); -PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_STRUCTSEQ_H */ + +/* Named tuple object interface */ + +#ifndef Py_STRUCTSEQ_H +#define Py_STRUCTSEQ_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PyStructSequence_Field { + char *name; + char *doc; +} PyStructSequence_Field; + +typedef struct PyStructSequence_Desc { + char *name; + char *doc; + struct PyStructSequence_Field *fields; + int n_in_sequence; +} PyStructSequence_Desc; + +extern char* PyStructSequence_UnnamedField; + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, + PyStructSequence_Desc *desc); +PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, + PyStructSequence_Desc *desc); +#endif +PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); + +PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); + +#ifndef Py_LIMITED_API +typedef PyTupleObject PyStructSequence; + +/* Macro, *only* to be used to fill in brand new objects */ +#define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM(op, i, v) + +#define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM(op, i) +#endif + +PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); +PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_STRUCTSEQ_H */ diff --git a/libs/nxpy/include/symtable.h b/libs/nxpy/include/symtable.h index 1409cd91..c0cfd5a3 100644 --- a/libs/nxpy/include/symtable.h +++ b/libs/nxpy/include/symtable.h @@ -1,117 +1,117 @@ -#ifndef Py_LIMITED_API -#ifndef Py_SYMTABLE_H -#define Py_SYMTABLE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* XXX(ncoghlan): This is a weird mix of public names and interpreter internal - * names. - */ - -typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock } - _Py_block_ty; - -struct _symtable_entry; - -struct symtable { - PyObject *st_filename; /* name of file being compiled, - decoded from the filesystem encoding */ - struct _symtable_entry *st_cur; /* current symbol table entry */ - struct _symtable_entry *st_top; /* symbol table entry for module */ - PyObject *st_blocks; /* dict: map AST node addresses - * to symbol table entries */ - PyObject *st_stack; /* list: stack of namespace info */ - PyObject *st_global; /* borrowed ref to st_top->ste_symbols */ - int st_nblocks; /* number of blocks used. kept for - consistency with the corresponding - compiler structure */ - PyObject *st_private; /* name of current class or NULL */ - PyFutureFeatures *st_future; /* module's future features that affect - the symbol table */ - int recursion_depth; /* current recursion depth */ - int recursion_limit; /* recursion limit */ -}; - -typedef struct _symtable_entry { - PyObject_HEAD - PyObject *ste_id; /* int: key in ste_table->st_blocks */ - PyObject *ste_symbols; /* dict: variable names to flags */ - PyObject *ste_name; /* string: name of current block */ - PyObject *ste_varnames; /* list of function parameters */ - PyObject *ste_children; /* list of child blocks */ - PyObject *ste_directives;/* locations of global and nonlocal statements */ - _Py_block_ty ste_type; /* module, class, or function */ - int ste_nested; /* true if block is nested */ - unsigned ste_free : 1; /* true if block has free variables */ - unsigned ste_child_free : 1; /* true if a child block has free vars, - including free refs to globals */ - unsigned ste_generator : 1; /* true if namespace is a generator */ - unsigned ste_varargs : 1; /* true if block has varargs */ - unsigned ste_varkeywords : 1; /* true if block has varkeywords */ - unsigned ste_returns_value : 1; /* true if namespace uses return with - an argument */ - unsigned ste_needs_class_closure : 1; /* for class scopes, true if a - closure over __class__ - should be created */ - int ste_lineno; /* first line of block */ - int ste_col_offset; /* offset of first line of block */ - int ste_opt_lineno; /* lineno of last exec or import * */ - int ste_opt_col_offset; /* offset of last exec or import * */ - int ste_tmpname; /* counter for listcomp temp vars */ - struct symtable *ste_table; -} PySTEntryObject; - -PyAPI_DATA(PyTypeObject) PySTEntry_Type; - -#define PySTEntry_Check(op) (Py_TYPE(op) == &PySTEntry_Type) - -PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *); - -PyAPI_FUNC(struct symtable *) PySymtable_Build( - mod_ty mod, - const char *filename, /* decoded from the filesystem encoding */ - PyFutureFeatures *future); -PyAPI_FUNC(struct symtable *) PySymtable_BuildObject( - mod_ty mod, - PyObject *filename, - PyFutureFeatures *future); -PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *); - -PyAPI_FUNC(void) PySymtable_Free(struct symtable *); - -/* Flags for def-use information */ - -#define DEF_GLOBAL 1 /* global stmt */ -#define DEF_LOCAL 2 /* assignment in code block */ -#define DEF_PARAM 2<<1 /* formal parameter */ -#define DEF_NONLOCAL 2<<2 /* nonlocal stmt */ -#define USE 2<<3 /* name is used */ -#define DEF_FREE 2<<4 /* name used but not defined in nested block */ -#define DEF_FREE_CLASS 2<<5 /* free variable from class's method */ -#define DEF_IMPORT 2<<6 /* assignment occurred via import */ - -#define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) - -/* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol - table. GLOBAL is returned from PyST_GetScope() for either of them. - It is stored in ste_symbols at bits 12-15. -*/ -#define SCOPE_OFFSET 11 -#define SCOPE_MASK (DEF_GLOBAL | DEF_LOCAL | DEF_PARAM | DEF_NONLOCAL) - -#define LOCAL 1 -#define GLOBAL_EXPLICIT 2 -#define GLOBAL_IMPLICIT 3 -#define FREE 4 -#define CELL 5 - -#define GENERATOR 1 -#define GENERATOR_EXPRESSION 2 - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SYMTABLE_H */ -#endif /* Py_LIMITED_API */ +#ifndef Py_LIMITED_API +#ifndef Py_SYMTABLE_H +#define Py_SYMTABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* XXX(ncoghlan): This is a weird mix of public names and interpreter internal + * names. + */ + +typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock } + _Py_block_ty; + +struct _symtable_entry; + +struct symtable { + PyObject *st_filename; /* name of file being compiled, + decoded from the filesystem encoding */ + struct _symtable_entry *st_cur; /* current symbol table entry */ + struct _symtable_entry *st_top; /* symbol table entry for module */ + PyObject *st_blocks; /* dict: map AST node addresses + * to symbol table entries */ + PyObject *st_stack; /* list: stack of namespace info */ + PyObject *st_global; /* borrowed ref to st_top->ste_symbols */ + int st_nblocks; /* number of blocks used. kept for + consistency with the corresponding + compiler structure */ + PyObject *st_private; /* name of current class or NULL */ + PyFutureFeatures *st_future; /* module's future features that affect + the symbol table */ + int recursion_depth; /* current recursion depth */ + int recursion_limit; /* recursion limit */ +}; + +typedef struct _symtable_entry { + PyObject_HEAD + PyObject *ste_id; /* int: key in ste_table->st_blocks */ + PyObject *ste_symbols; /* dict: variable names to flags */ + PyObject *ste_name; /* string: name of current block */ + PyObject *ste_varnames; /* list of function parameters */ + PyObject *ste_children; /* list of child blocks */ + PyObject *ste_directives;/* locations of global and nonlocal statements */ + _Py_block_ty ste_type; /* module, class, or function */ + int ste_nested; /* true if block is nested */ + unsigned ste_free : 1; /* true if block has free variables */ + unsigned ste_child_free : 1; /* true if a child block has free vars, + including free refs to globals */ + unsigned ste_generator : 1; /* true if namespace is a generator */ + unsigned ste_varargs : 1; /* true if block has varargs */ + unsigned ste_varkeywords : 1; /* true if block has varkeywords */ + unsigned ste_returns_value : 1; /* true if namespace uses return with + an argument */ + unsigned ste_needs_class_closure : 1; /* for class scopes, true if a + closure over __class__ + should be created */ + int ste_lineno; /* first line of block */ + int ste_col_offset; /* offset of first line of block */ + int ste_opt_lineno; /* lineno of last exec or import * */ + int ste_opt_col_offset; /* offset of last exec or import * */ + int ste_tmpname; /* counter for listcomp temp vars */ + struct symtable *ste_table; +} PySTEntryObject; + +PyAPI_DATA(PyTypeObject) PySTEntry_Type; + +#define PySTEntry_Check(op) (Py_TYPE(op) == &PySTEntry_Type) + +PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *); + +PyAPI_FUNC(struct symtable *) PySymtable_Build( + mod_ty mod, + const char *filename, /* decoded from the filesystem encoding */ + PyFutureFeatures *future); +PyAPI_FUNC(struct symtable *) PySymtable_BuildObject( + mod_ty mod, + PyObject *filename, + PyFutureFeatures *future); +PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *); + +PyAPI_FUNC(void) PySymtable_Free(struct symtable *); + +/* Flags for def-use information */ + +#define DEF_GLOBAL 1 /* global stmt */ +#define DEF_LOCAL 2 /* assignment in code block */ +#define DEF_PARAM 2<<1 /* formal parameter */ +#define DEF_NONLOCAL 2<<2 /* nonlocal stmt */ +#define USE 2<<3 /* name is used */ +#define DEF_FREE 2<<4 /* name used but not defined in nested block */ +#define DEF_FREE_CLASS 2<<5 /* free variable from class's method */ +#define DEF_IMPORT 2<<6 /* assignment occurred via import */ + +#define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) + +/* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol + table. GLOBAL is returned from PyST_GetScope() for either of them. + It is stored in ste_symbols at bits 12-15. +*/ +#define SCOPE_OFFSET 11 +#define SCOPE_MASK (DEF_GLOBAL | DEF_LOCAL | DEF_PARAM | DEF_NONLOCAL) + +#define LOCAL 1 +#define GLOBAL_EXPLICIT 2 +#define GLOBAL_IMPLICIT 3 +#define FREE 4 +#define CELL 5 + +#define GENERATOR 1 +#define GENERATOR_EXPRESSION 2 + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SYMTABLE_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/sysmodule.h b/libs/nxpy/include/sysmodule.h index cde10ac4..bf64ca0c 100644 --- a/libs/nxpy/include/sysmodule.h +++ b/libs/nxpy/include/sysmodule.h @@ -1,43 +1,43 @@ - -/* System module interface */ - -#ifndef Py_SYSMODULE_H -#define Py_SYSMODULE_H -#ifdef __cplusplus -extern "C" { -#endif - -PyAPI_FUNC(PyObject *) PySys_GetObject(const char *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key); -#endif -PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *); -PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *); - -PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **); -PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int); -PyAPI_FUNC(void) PySys_SetPath(const wchar_t *); - -PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) - Py_GCC_ATTRIBUTE((format(printf, 1, 2))); -PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...); -PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...); - -PyAPI_FUNC(void) PySys_ResetWarnOptions(void); -PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *); -PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *); -PyAPI_FUNC(int) PySys_HasWarnOptions(void); - -PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); -PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_SYSMODULE_H */ + +/* System module interface */ + +#ifndef Py_SYSMODULE_H +#define Py_SYSMODULE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(PyObject *) PySys_GetObject(const char *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key); +#endif +PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *); +PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *); + +PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **); +PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int); +PyAPI_FUNC(void) PySys_SetPath(const wchar_t *); + +PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...); +PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...); + +PyAPI_FUNC(void) PySys_ResetWarnOptions(void); +PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *); +PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *); +PyAPI_FUNC(int) PySys_HasWarnOptions(void); + +PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); +PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SYSMODULE_H */ diff --git a/libs/nxpy/include/token.h b/libs/nxpy/include/token.h index 595afa01..e084ca56 100644 --- a/libs/nxpy/include/token.h +++ b/libs/nxpy/include/token.h @@ -1,90 +1,90 @@ - -/* Token types */ -#ifndef Py_LIMITED_API -#ifndef Py_TOKEN_H -#define Py_TOKEN_H -#ifdef __cplusplus -extern "C" { -#endif - -#undef TILDE /* Prevent clash of our definition with system macro. Ex AIX, ioctl.h */ - -#define ENDMARKER 0 -#define NAME 1 -#define NUMBER 2 -#define STRING 3 -#define NEWLINE 4 -#define INDENT 5 -#define DEDENT 6 -#define LPAR 7 -#define RPAR 8 -#define LSQB 9 -#define RSQB 10 -#define COLON 11 -#define COMMA 12 -#define SEMI 13 -#define PLUS 14 -#define MINUS 15 -#define STAR 16 -#define SLASH 17 -#define VBAR 18 -#define AMPER 19 -#define LESS 20 -#define GREATER 21 -#define EQUAL 22 -#define DOT 23 -#define PERCENT 24 -#define LBRACE 25 -#define RBRACE 26 -#define EQEQUAL 27 -#define NOTEQUAL 28 -#define LESSEQUAL 29 -#define GREATEREQUAL 30 -#define TILDE 31 -#define CIRCUMFLEX 32 -#define LEFTSHIFT 33 -#define RIGHTSHIFT 34 -#define DOUBLESTAR 35 -#define PLUSEQUAL 36 -#define MINEQUAL 37 -#define STAREQUAL 38 -#define SLASHEQUAL 39 -#define PERCENTEQUAL 40 -#define AMPEREQUAL 41 -#define VBAREQUAL 42 -#define CIRCUMFLEXEQUAL 43 -#define LEFTSHIFTEQUAL 44 -#define RIGHTSHIFTEQUAL 45 -#define DOUBLESTAREQUAL 46 -#define DOUBLESLASH 47 -#define DOUBLESLASHEQUAL 48 -#define AT 49 -#define ATEQUAL 50 -#define RARROW 51 -#define ELLIPSIS 52 -/* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */ -#define OP 53 -#define AWAIT 54 -#define ASYNC 55 -#define ERRORTOKEN 56 -#define N_TOKENS 57 - -/* Special definitions for cooperation with parser */ - -#define NT_OFFSET 256 - -#define ISTERMINAL(x) ((x) < NT_OFFSET) -#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) -#define ISEOF(x) ((x) == ENDMARKER) - - -PyAPI_DATA(const char *) _PyParser_TokenNames[]; /* Token names */ -PyAPI_FUNC(int) PyToken_OneChar(int); -PyAPI_FUNC(int) PyToken_TwoChars(int, int); -PyAPI_FUNC(int) PyToken_ThreeChars(int, int, int); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TOKEN_H */ -#endif /* Py_LIMITED_API */ + +/* Token types */ +#ifndef Py_LIMITED_API +#ifndef Py_TOKEN_H +#define Py_TOKEN_H +#ifdef __cplusplus +extern "C" { +#endif + +#undef TILDE /* Prevent clash of our definition with system macro. Ex AIX, ioctl.h */ + +#define ENDMARKER 0 +#define NAME 1 +#define NUMBER 2 +#define STRING 3 +#define NEWLINE 4 +#define INDENT 5 +#define DEDENT 6 +#define LPAR 7 +#define RPAR 8 +#define LSQB 9 +#define RSQB 10 +#define COLON 11 +#define COMMA 12 +#define SEMI 13 +#define PLUS 14 +#define MINUS 15 +#define STAR 16 +#define SLASH 17 +#define VBAR 18 +#define AMPER 19 +#define LESS 20 +#define GREATER 21 +#define EQUAL 22 +#define DOT 23 +#define PERCENT 24 +#define LBRACE 25 +#define RBRACE 26 +#define EQEQUAL 27 +#define NOTEQUAL 28 +#define LESSEQUAL 29 +#define GREATEREQUAL 30 +#define TILDE 31 +#define CIRCUMFLEX 32 +#define LEFTSHIFT 33 +#define RIGHTSHIFT 34 +#define DOUBLESTAR 35 +#define PLUSEQUAL 36 +#define MINEQUAL 37 +#define STAREQUAL 38 +#define SLASHEQUAL 39 +#define PERCENTEQUAL 40 +#define AMPEREQUAL 41 +#define VBAREQUAL 42 +#define CIRCUMFLEXEQUAL 43 +#define LEFTSHIFTEQUAL 44 +#define RIGHTSHIFTEQUAL 45 +#define DOUBLESTAREQUAL 46 +#define DOUBLESLASH 47 +#define DOUBLESLASHEQUAL 48 +#define AT 49 +#define ATEQUAL 50 +#define RARROW 51 +#define ELLIPSIS 52 +/* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */ +#define OP 53 +#define AWAIT 54 +#define ASYNC 55 +#define ERRORTOKEN 56 +#define N_TOKENS 57 + +/* Special definitions for cooperation with parser */ + +#define NT_OFFSET 256 + +#define ISTERMINAL(x) ((x) < NT_OFFSET) +#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) +#define ISEOF(x) ((x) == ENDMARKER) + + +PyAPI_DATA(const char *) _PyParser_TokenNames[]; /* Token names */ +PyAPI_FUNC(int) PyToken_OneChar(int); +PyAPI_FUNC(int) PyToken_TwoChars(int, int); +PyAPI_FUNC(int) PyToken_ThreeChars(int, int, int); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TOKEN_H */ +#endif /* Py_LIMITED_API */ diff --git a/libs/nxpy/include/traceback.h b/libs/nxpy/include/traceback.h index c3ecbe29..965ac898 100644 --- a/libs/nxpy/include/traceback.h +++ b/libs/nxpy/include/traceback.h @@ -1,73 +1,73 @@ - -#ifndef Py_TRACEBACK_H -#define Py_TRACEBACK_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "pystate.h" - -struct _frame; - -/* Traceback interface */ -#ifndef Py_LIMITED_API -typedef struct _traceback { - PyObject_HEAD - struct _traceback *tb_next; - struct _frame *tb_frame; - int tb_lasti; - int tb_lineno; -} PyTracebackObject; -#endif - -PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *); -PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int); -PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int); -#endif - -/* Reveal traceback type so we can typecheck traceback objects */ -PyAPI_DATA(PyTypeObject) PyTraceBack_Type; -#define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type) - -/* Write the Python traceback into the file 'fd'. For example: - - Traceback (most recent call first): - File "xxx", line xxx in - File "xxx", line xxx in - ... - File "xxx", line xxx in - - This function is written for debug purpose only, to dump the traceback in - the worst case: after a segmentation fault, at fatal error, etc. That's why, - it is very limited. Strings are truncated to 100 characters and encoded to - ASCII with backslashreplace. It doesn't write the source code, only the - function name, filename and line number of each frame. Write only the first - 100 frames: if the traceback is truncated, write the line " ...". - - This function is signal safe. */ - -PyAPI_FUNC(void) _Py_DumpTraceback( - int fd, - PyThreadState *tstate); - -/* Write the traceback of all threads into the file 'fd'. current_thread can be - NULL. Return NULL on success, or an error message on error. - - This function is written for debug purpose only. It calls - _Py_DumpTraceback() for each thread, and so has the same limitations. It - only write the traceback of the first 100 threads: write "..." if there are - more threads. - - This function is signal safe. */ - -PyAPI_FUNC(const char*) _Py_DumpTracebackThreads( - int fd, PyInterpreterState *interp, - PyThreadState *current_thread); - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TRACEBACK_H */ + +#ifndef Py_TRACEBACK_H +#define Py_TRACEBACK_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "pystate.h" + +struct _frame; + +/* Traceback interface */ +#ifndef Py_LIMITED_API +typedef struct _traceback { + PyObject_HEAD + struct _traceback *tb_next; + struct _frame *tb_frame; + int tb_lasti; + int tb_lineno; +} PyTracebackObject; +#endif + +PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *); +PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int); +PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int); +#endif + +/* Reveal traceback type so we can typecheck traceback objects */ +PyAPI_DATA(PyTypeObject) PyTraceBack_Type; +#define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type) + +/* Write the Python traceback into the file 'fd'. For example: + + Traceback (most recent call first): + File "xxx", line xxx in + File "xxx", line xxx in + ... + File "xxx", line xxx in + + This function is written for debug purpose only, to dump the traceback in + the worst case: after a segmentation fault, at fatal error, etc. That's why, + it is very limited. Strings are truncated to 100 characters and encoded to + ASCII with backslashreplace. It doesn't write the source code, only the + function name, filename and line number of each frame. Write only the first + 100 frames: if the traceback is truncated, write the line " ...". + + This function is signal safe. */ + +PyAPI_FUNC(void) _Py_DumpTraceback( + int fd, + PyThreadState *tstate); + +/* Write the traceback of all threads into the file 'fd'. current_thread can be + NULL. Return NULL on success, or an error message on error. + + This function is written for debug purpose only. It calls + _Py_DumpTraceback() for each thread, and so has the same limitations. It + only write the traceback of the first 100 threads: write "..." if there are + more threads. + + This function is signal safe. */ + +PyAPI_FUNC(const char*) _Py_DumpTracebackThreads( + int fd, PyInterpreterState *interp, + PyThreadState *current_thread); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TRACEBACK_H */ diff --git a/libs/nxpy/include/tupleobject.h b/libs/nxpy/include/tupleobject.h index c273ce7d..d2e39973 100644 --- a/libs/nxpy/include/tupleobject.h +++ b/libs/nxpy/include/tupleobject.h @@ -1,73 +1,73 @@ - -/* Tuple object interface */ - -#ifndef Py_TUPLEOBJECT_H -#define Py_TUPLEOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* -Another generally useful object type is a tuple of object pointers. -For Python, this is an immutable type. C code can change the tuple items -(but not their number), and even use tuples are general-purpose arrays of -object references, but in general only brand new tuples should be mutated, -not ones that might already have been exposed to Python code. - -*** WARNING *** PyTuple_SetItem does not increment the new item's reference -count, but does decrement the reference count of the item it replaces, -if not nil. It does *decrement* the reference count if it is *not* -inserted in the tuple. Similarly, PyTuple_GetItem does not increment the -returned item's reference count. -*/ - -#ifndef Py_LIMITED_API -typedef struct { - PyObject_VAR_HEAD - PyObject *ob_item[1]; - - /* ob_item contains space for 'ob_size' elements. - * Items must normally not be NULL, except during construction when - * the tuple is not yet visible outside the function that builds it. - */ -} PyTupleObject; -#endif - -PyAPI_DATA(PyTypeObject) PyTuple_Type; -PyAPI_DATA(PyTypeObject) PyTupleIter_Type; - -#define PyTuple_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS) -#define PyTuple_CheckExact(op) (Py_TYPE(op) == &PyTuple_Type) - -PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); -PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *); -PyAPI_FUNC(PyObject *) PyTuple_GetItem(PyObject *, Py_ssize_t); -PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *); -PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyTuple_Resize(PyObject **, Py_ssize_t); -#endif -PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *); -#endif - -/* Macro, trading safety for speed */ -#ifndef Py_LIMITED_API -#define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i]) -#define PyTuple_GET_SIZE(op) Py_SIZE(op) - -/* Macro, *only* to be used to fill in brand new tuples */ -#define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v) -#endif - -PyAPI_FUNC(int) PyTuple_ClearFreeList(void); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out); -#endif /* Py_LIMITED_API */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_TUPLEOBJECT_H */ + +/* Tuple object interface */ + +#ifndef Py_TUPLEOBJECT_H +#define Py_TUPLEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* +Another generally useful object type is a tuple of object pointers. +For Python, this is an immutable type. C code can change the tuple items +(but not their number), and even use tuples are general-purpose arrays of +object references, but in general only brand new tuples should be mutated, +not ones that might already have been exposed to Python code. + +*** WARNING *** PyTuple_SetItem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the tuple. Similarly, PyTuple_GetItem does not increment the +returned item's reference count. +*/ + +#ifndef Py_LIMITED_API +typedef struct { + PyObject_VAR_HEAD + PyObject *ob_item[1]; + + /* ob_item contains space for 'ob_size' elements. + * Items must normally not be NULL, except during construction when + * the tuple is not yet visible outside the function that builds it. + */ +} PyTupleObject; +#endif + +PyAPI_DATA(PyTypeObject) PyTuple_Type; +PyAPI_DATA(PyTypeObject) PyTupleIter_Type; + +#define PyTuple_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS) +#define PyTuple_CheckExact(op) (Py_TYPE(op) == &PyTuple_Type) + +PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); +PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *); +PyAPI_FUNC(PyObject *) PyTuple_GetItem(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyTuple_Resize(PyObject **, Py_ssize_t); +#endif +PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *); +#endif + +/* Macro, trading safety for speed */ +#ifndef Py_LIMITED_API +#define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i]) +#define PyTuple_GET_SIZE(op) Py_SIZE(op) + +/* Macro, *only* to be used to fill in brand new tuples */ +#define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v) +#endif + +PyAPI_FUNC(int) PyTuple_ClearFreeList(void); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out); +#endif /* Py_LIMITED_API */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TUPLEOBJECT_H */ diff --git a/libs/nxpy/include/typeslots.h b/libs/nxpy/include/typeslots.h index 0ce6a377..bf382f07 100644 --- a/libs/nxpy/include/typeslots.h +++ b/libs/nxpy/include/typeslots.h @@ -1,85 +1,85 @@ -/* Do not renumber the file; these numbers are part of the stable ABI. */ -/* Disabled, see #10181 */ -#undef Py_bf_getbuffer -#undef Py_bf_releasebuffer -#define Py_mp_ass_subscript 3 -#define Py_mp_length 4 -#define Py_mp_subscript 5 -#define Py_nb_absolute 6 -#define Py_nb_add 7 -#define Py_nb_and 8 -#define Py_nb_bool 9 -#define Py_nb_divmod 10 -#define Py_nb_float 11 -#define Py_nb_floor_divide 12 -#define Py_nb_index 13 -#define Py_nb_inplace_add 14 -#define Py_nb_inplace_and 15 -#define Py_nb_inplace_floor_divide 16 -#define Py_nb_inplace_lshift 17 -#define Py_nb_inplace_multiply 18 -#define Py_nb_inplace_or 19 -#define Py_nb_inplace_power 20 -#define Py_nb_inplace_remainder 21 -#define Py_nb_inplace_rshift 22 -#define Py_nb_inplace_subtract 23 -#define Py_nb_inplace_true_divide 24 -#define Py_nb_inplace_xor 25 -#define Py_nb_int 26 -#define Py_nb_invert 27 -#define Py_nb_lshift 28 -#define Py_nb_multiply 29 -#define Py_nb_negative 30 -#define Py_nb_or 31 -#define Py_nb_positive 32 -#define Py_nb_power 33 -#define Py_nb_remainder 34 -#define Py_nb_rshift 35 -#define Py_nb_subtract 36 -#define Py_nb_true_divide 37 -#define Py_nb_xor 38 -#define Py_sq_ass_item 39 -#define Py_sq_concat 40 -#define Py_sq_contains 41 -#define Py_sq_inplace_concat 42 -#define Py_sq_inplace_repeat 43 -#define Py_sq_item 44 -#define Py_sq_length 45 -#define Py_sq_repeat 46 -#define Py_tp_alloc 47 -#define Py_tp_base 48 -#define Py_tp_bases 49 -#define Py_tp_call 50 -#define Py_tp_clear 51 -#define Py_tp_dealloc 52 -#define Py_tp_del 53 -#define Py_tp_descr_get 54 -#define Py_tp_descr_set 55 -#define Py_tp_doc 56 -#define Py_tp_getattr 57 -#define Py_tp_getattro 58 -#define Py_tp_hash 59 -#define Py_tp_init 60 -#define Py_tp_is_gc 61 -#define Py_tp_iter 62 -#define Py_tp_iternext 63 -#define Py_tp_methods 64 -#define Py_tp_new 65 -#define Py_tp_repr 66 -#define Py_tp_richcompare 67 -#define Py_tp_setattr 68 -#define Py_tp_setattro 69 -#define Py_tp_str 70 -#define Py_tp_traverse 71 -#define Py_tp_members 72 -#define Py_tp_getset 73 -#define Py_tp_free 74 -#define Py_nb_matrix_multiply 75 -#define Py_nb_inplace_matrix_multiply 76 -#define Py_am_await 77 -#define Py_am_aiter 78 -#define Py_am_anext 79 -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 -/* New in 3.5 */ -#define Py_tp_finalize 80 -#endif +/* Do not renumber the file; these numbers are part of the stable ABI. */ +/* Disabled, see #10181 */ +#undef Py_bf_getbuffer +#undef Py_bf_releasebuffer +#define Py_mp_ass_subscript 3 +#define Py_mp_length 4 +#define Py_mp_subscript 5 +#define Py_nb_absolute 6 +#define Py_nb_add 7 +#define Py_nb_and 8 +#define Py_nb_bool 9 +#define Py_nb_divmod 10 +#define Py_nb_float 11 +#define Py_nb_floor_divide 12 +#define Py_nb_index 13 +#define Py_nb_inplace_add 14 +#define Py_nb_inplace_and 15 +#define Py_nb_inplace_floor_divide 16 +#define Py_nb_inplace_lshift 17 +#define Py_nb_inplace_multiply 18 +#define Py_nb_inplace_or 19 +#define Py_nb_inplace_power 20 +#define Py_nb_inplace_remainder 21 +#define Py_nb_inplace_rshift 22 +#define Py_nb_inplace_subtract 23 +#define Py_nb_inplace_true_divide 24 +#define Py_nb_inplace_xor 25 +#define Py_nb_int 26 +#define Py_nb_invert 27 +#define Py_nb_lshift 28 +#define Py_nb_multiply 29 +#define Py_nb_negative 30 +#define Py_nb_or 31 +#define Py_nb_positive 32 +#define Py_nb_power 33 +#define Py_nb_remainder 34 +#define Py_nb_rshift 35 +#define Py_nb_subtract 36 +#define Py_nb_true_divide 37 +#define Py_nb_xor 38 +#define Py_sq_ass_item 39 +#define Py_sq_concat 40 +#define Py_sq_contains 41 +#define Py_sq_inplace_concat 42 +#define Py_sq_inplace_repeat 43 +#define Py_sq_item 44 +#define Py_sq_length 45 +#define Py_sq_repeat 46 +#define Py_tp_alloc 47 +#define Py_tp_base 48 +#define Py_tp_bases 49 +#define Py_tp_call 50 +#define Py_tp_clear 51 +#define Py_tp_dealloc 52 +#define Py_tp_del 53 +#define Py_tp_descr_get 54 +#define Py_tp_descr_set 55 +#define Py_tp_doc 56 +#define Py_tp_getattr 57 +#define Py_tp_getattro 58 +#define Py_tp_hash 59 +#define Py_tp_init 60 +#define Py_tp_is_gc 61 +#define Py_tp_iter 62 +#define Py_tp_iternext 63 +#define Py_tp_methods 64 +#define Py_tp_new 65 +#define Py_tp_repr 66 +#define Py_tp_richcompare 67 +#define Py_tp_setattr 68 +#define Py_tp_setattro 69 +#define Py_tp_str 70 +#define Py_tp_traverse 71 +#define Py_tp_members 72 +#define Py_tp_getset 73 +#define Py_tp_free 74 +#define Py_nb_matrix_multiply 75 +#define Py_nb_inplace_matrix_multiply 76 +#define Py_am_await 77 +#define Py_am_aiter 78 +#define Py_am_anext 79 +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000 +/* New in 3.5 */ +#define Py_tp_finalize 80 +#endif diff --git a/libs/nxpy/include/ucnhash.h b/libs/nxpy/include/ucnhash.h index 45362e99..6d1a29fb 100644 --- a/libs/nxpy/include/ucnhash.h +++ b/libs/nxpy/include/ucnhash.h @@ -1,36 +1,36 @@ -/* Unicode name database interface */ -#ifndef Py_LIMITED_API -#ifndef Py_UCNHASH_H -#define Py_UCNHASH_H -#ifdef __cplusplus -extern "C" { -#endif - -/* revised ucnhash CAPI interface (exported through a "wrapper") */ - -#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI" - -typedef struct { - - /* Size of this struct */ - int size; - - /* Get name for a given character code. Returns non-zero if - success, zero if not. Does not set Python exceptions. - If self is NULL, data come from the default version of the database. - If it is not NULL, it should be a unicodedata.ucd_X_Y_Z object */ - int (*getname)(PyObject *self, Py_UCS4 code, char* buffer, int buflen, - int with_alias_and_seq); - - /* Get character code for a given name. Same error handling - as for getname. */ - int (*getcode)(PyObject *self, const char* name, int namelen, Py_UCS4* code, - int with_named_seq); - -} _PyUnicode_Name_CAPI; - -#ifdef __cplusplus -} -#endif -#endif /* !Py_UCNHASH_H */ -#endif /* !Py_LIMITED_API */ +/* Unicode name database interface */ +#ifndef Py_LIMITED_API +#ifndef Py_UCNHASH_H +#define Py_UCNHASH_H +#ifdef __cplusplus +extern "C" { +#endif + +/* revised ucnhash CAPI interface (exported through a "wrapper") */ + +#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI" + +typedef struct { + + /* Size of this struct */ + int size; + + /* Get name for a given character code. Returns non-zero if + success, zero if not. Does not set Python exceptions. + If self is NULL, data come from the default version of the database. + If it is not NULL, it should be a unicodedata.ucd_X_Y_Z object */ + int (*getname)(PyObject *self, Py_UCS4 code, char* buffer, int buflen, + int with_alias_and_seq); + + /* Get character code for a given name. Same error handling + as for getname. */ + int (*getcode)(PyObject *self, const char* name, int namelen, Py_UCS4* code, + int with_named_seq); + +} _PyUnicode_Name_CAPI; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_UCNHASH_H */ +#endif /* !Py_LIMITED_API */ diff --git a/libs/nxpy/include/unicodeobject.h b/libs/nxpy/include/unicodeobject.h index 9308a6aa..76532b78 100644 --- a/libs/nxpy/include/unicodeobject.h +++ b/libs/nxpy/include/unicodeobject.h @@ -1,2285 +1,2285 @@ -#ifndef Py_UNICODEOBJECT_H -#define Py_UNICODEOBJECT_H - -#include - -/* - -Unicode implementation based on original code by Fredrik Lundh, -modified by Marc-Andre Lemburg (mal@lemburg.com) according to the -Unicode Integration Proposal. (See -http://www.egenix.com/files/python/unicode-proposal.txt). - -Copyright (c) Corporation for National Research Initiatives. - - - Original header: - -------------------------------------------------------------------- - - * Yet another Unicode string type for Python. This type supports the - * 16-bit Basic Multilingual Plane (BMP) only. - * - * Written by Fredrik Lundh, January 1999. - * - * Copyright (c) 1999 by Secret Labs AB. - * Copyright (c) 1999 by Fredrik Lundh. - * - * fredrik@pythonware.com - * http://www.pythonware.com - * - * -------------------------------------------------------------------- - * This Unicode String Type is - * - * Copyright (c) 1999 by Secret Labs AB - * Copyright (c) 1999 by Fredrik Lundh - * - * By obtaining, using, and/or copying this software and/or its - * associated documentation, you agree that you have read, understood, - * and will comply with the following terms and conditions: - * - * Permission to use, copy, modify, and distribute this software and its - * associated documentation for any purpose and without fee is hereby - * granted, provided that the above copyright notice appears in all - * copies, and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of Secret Labs - * AB or the author not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * -------------------------------------------------------------------- */ - -#include - -/* === Internal API ======================================================= */ - -/* --- Internal Unicode Format -------------------------------------------- */ - -/* Python 3.x requires unicode */ -#define Py_USING_UNICODE - -#ifndef SIZEOF_WCHAR_T -#error Must define SIZEOF_WCHAR_T -#endif - -#define Py_UNICODE_SIZE SIZEOF_WCHAR_T - -/* If wchar_t can be used for UCS-4 storage, set Py_UNICODE_WIDE. - Otherwise, Unicode strings are stored as UCS-2 (with limited support - for UTF-16) */ - -#if Py_UNICODE_SIZE >= 4 -#define Py_UNICODE_WIDE -#endif - -/* Set these flags if the platform has "wchar.h" and the - wchar_t type is a 16-bit unsigned type */ -/* #define HAVE_WCHAR_H */ -/* #define HAVE_USABLE_WCHAR_T */ - -/* Py_UNICODE was the native Unicode storage format (code unit) used by - Python and represents a single Unicode element in the Unicode type. - With PEP 393, Py_UNICODE is deprecated and replaced with a - typedef to wchar_t. */ - -#ifndef Py_LIMITED_API -#define PY_UNICODE_TYPE wchar_t -typedef wchar_t Py_UNICODE; -#endif - -/* If the compiler provides a wchar_t type we try to support it - through the interface functions PyUnicode_FromWideChar(), - PyUnicode_AsWideChar() and PyUnicode_AsWideCharString(). */ - -#ifdef HAVE_USABLE_WCHAR_T -# ifndef HAVE_WCHAR_H -# define HAVE_WCHAR_H -# endif -#endif - -#if defined(MS_WINDOWS) -# define HAVE_MBCS -#endif - -#ifdef HAVE_WCHAR_H -/* Work around a cosmetic bug in BSDI 4.x wchar.h; thanks to Thomas Wouters */ -# ifdef _HAVE_BSDI -# include -# endif -# include -#endif - -/* Py_UCS4 and Py_UCS2 are typedefs for the respective - unicode representations. */ -#if SIZEOF_INT == 4 -typedef unsigned int Py_UCS4; -#elif SIZEOF_LONG == 4 -typedef unsigned long Py_UCS4; -#else -#error "Could not find a proper typedef for Py_UCS4" -#endif - -#if SIZEOF_SHORT == 2 -typedef unsigned short Py_UCS2; -#else -#error "Could not find a proper typedef for Py_UCS2" -#endif - -typedef unsigned char Py_UCS1; - -/* --- Internal Unicode Operations ---------------------------------------- */ - -/* Since splitting on whitespace is an important use case, and - whitespace in most situations is solely ASCII whitespace, we - optimize for the common case by using a quick look-up table - _Py_ascii_whitespace (see below) with an inlined check. - - */ -#ifndef Py_LIMITED_API -#define Py_UNICODE_ISSPACE(ch) \ - ((ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch)) - -#define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch) -#define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch) -#define Py_UNICODE_ISTITLE(ch) _PyUnicode_IsTitlecase(ch) -#define Py_UNICODE_ISLINEBREAK(ch) _PyUnicode_IsLinebreak(ch) - -#define Py_UNICODE_TOLOWER(ch) _PyUnicode_ToLowercase(ch) -#define Py_UNICODE_TOUPPER(ch) _PyUnicode_ToUppercase(ch) -#define Py_UNICODE_TOTITLE(ch) _PyUnicode_ToTitlecase(ch) - -#define Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch) -#define Py_UNICODE_ISDIGIT(ch) _PyUnicode_IsDigit(ch) -#define Py_UNICODE_ISNUMERIC(ch) _PyUnicode_IsNumeric(ch) -#define Py_UNICODE_ISPRINTABLE(ch) _PyUnicode_IsPrintable(ch) - -#define Py_UNICODE_TODECIMAL(ch) _PyUnicode_ToDecimalDigit(ch) -#define Py_UNICODE_TODIGIT(ch) _PyUnicode_ToDigit(ch) -#define Py_UNICODE_TONUMERIC(ch) _PyUnicode_ToNumeric(ch) - -#define Py_UNICODE_ISALPHA(ch) _PyUnicode_IsAlpha(ch) - -#define Py_UNICODE_ISALNUM(ch) \ - (Py_UNICODE_ISALPHA(ch) || \ - Py_UNICODE_ISDECIMAL(ch) || \ - Py_UNICODE_ISDIGIT(ch) || \ - Py_UNICODE_ISNUMERIC(ch)) - -#define Py_UNICODE_COPY(target, source, length) \ - Py_MEMCPY((target), (source), (length)*sizeof(Py_UNICODE)) - -#define Py_UNICODE_FILL(target, value, length) \ - do {Py_ssize_t i_; Py_UNICODE *t_ = (target); Py_UNICODE v_ = (value);\ - for (i_ = 0; i_ < (length); i_++) t_[i_] = v_;\ - } while (0) - -/* macros to work with surrogates */ -#define Py_UNICODE_IS_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDFFF) -#define Py_UNICODE_IS_HIGH_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDBFF) -#define Py_UNICODE_IS_LOW_SURROGATE(ch) (0xDC00 <= (ch) && (ch) <= 0xDFFF) -/* Join two surrogate characters and return a single Py_UCS4 value. */ -#define Py_UNICODE_JOIN_SURROGATES(high, low) \ - (((((Py_UCS4)(high) & 0x03FF) << 10) | \ - ((Py_UCS4)(low) & 0x03FF)) + 0x10000) -/* high surrogate = top 10 bits added to D800 */ -#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10)) -/* low surrogate = bottom 10 bits added to DC00 */ -#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF)) - -/* Check if substring matches at given offset. The offset must be - valid, and the substring must not be empty. */ - -#define Py_UNICODE_MATCH(string, offset, substring) \ - ((*((string)->wstr + (offset)) == *((substring)->wstr)) && \ - ((*((string)->wstr + (offset) + (substring)->wstr_length-1) == *((substring)->wstr + (substring)->wstr_length-1))) && \ - !memcmp((string)->wstr + (offset), (substring)->wstr, (substring)->wstr_length*sizeof(Py_UNICODE))) - -#endif /* Py_LIMITED_API */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* --- Unicode Type ------------------------------------------------------- */ - -#ifndef Py_LIMITED_API - -/* ASCII-only strings created through PyUnicode_New use the PyASCIIObject - structure. state.ascii and state.compact are set, and the data - immediately follow the structure. utf8_length and wstr_length can be found - in the length field; the utf8 pointer is equal to the data pointer. */ -typedef struct { - /* There are 4 forms of Unicode strings: - - - compact ascii: - - * structure = PyASCIIObject - * test: PyUnicode_IS_COMPACT_ASCII(op) - * kind = PyUnicode_1BYTE_KIND - * compact = 1 - * ascii = 1 - * ready = 1 - * (length is the length of the utf8 and wstr strings) - * (data starts just after the structure) - * (since ASCII is decoded from UTF-8, the utf8 string are the data) - - - compact: - - * structure = PyCompactUnicodeObject - * test: PyUnicode_IS_COMPACT(op) && !PyUnicode_IS_ASCII(op) - * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or - PyUnicode_4BYTE_KIND - * compact = 1 - * ready = 1 - * ascii = 0 - * utf8 is not shared with data - * utf8_length = 0 if utf8 is NULL - * wstr is shared with data and wstr_length=length - if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 - or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_t)=4 - * wstr_length = 0 if wstr is NULL - * (data starts just after the structure) - - - legacy string, not ready: - - * structure = PyUnicodeObject - * test: kind == PyUnicode_WCHAR_KIND - * length = 0 (use wstr_length) - * hash = -1 - * kind = PyUnicode_WCHAR_KIND - * compact = 0 - * ascii = 0 - * ready = 0 - * interned = SSTATE_NOT_INTERNED - * wstr is not NULL - * data.any is NULL - * utf8 is NULL - * utf8_length = 0 - - - legacy string, ready: - - * structure = PyUnicodeObject structure - * test: !PyUnicode_IS_COMPACT(op) && kind != PyUnicode_WCHAR_KIND - * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or - PyUnicode_4BYTE_KIND - * compact = 0 - * ready = 1 - * data.any is not NULL - * utf8 is shared and utf8_length = length with data.any if ascii = 1 - * utf8_length = 0 if utf8 is NULL - * wstr is shared with data.any and wstr_length = length - if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 - or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_4)=4 - * wstr_length = 0 if wstr is NULL - - Compact strings use only one memory block (structure + characters), - whereas legacy strings use one block for the structure and one block - for characters. - - Legacy strings are created by PyUnicode_FromUnicode() and - PyUnicode_FromStringAndSize(NULL, size) functions. They become ready - when PyUnicode_READY() is called. - - See also _PyUnicode_CheckConsistency(). - */ - PyObject_HEAD - Py_ssize_t length; /* Number of code points in the string */ - Py_hash_t hash; /* Hash value; -1 if not set */ - struct { - /* - SSTATE_NOT_INTERNED (0) - SSTATE_INTERNED_MORTAL (1) - SSTATE_INTERNED_IMMORTAL (2) - - If interned != SSTATE_NOT_INTERNED, the two references from the - dictionary to this object are *not* counted in ob_refcnt. - */ - unsigned int interned:2; - /* Character size: - - - PyUnicode_WCHAR_KIND (0): - - * character type = wchar_t (16 or 32 bits, depending on the - platform) - - - PyUnicode_1BYTE_KIND (1): - - * character type = Py_UCS1 (8 bits, unsigned) - * all characters are in the range U+0000-U+00FF (latin1) - * if ascii is set, all characters are in the range U+0000-U+007F - (ASCII), otherwise at least one character is in the range - U+0080-U+00FF - - - PyUnicode_2BYTE_KIND (2): - - * character type = Py_UCS2 (16 bits, unsigned) - * all characters are in the range U+0000-U+FFFF (BMP) - * at least one character is in the range U+0100-U+FFFF - - - PyUnicode_4BYTE_KIND (4): - - * character type = Py_UCS4 (32 bits, unsigned) - * all characters are in the range U+0000-U+10FFFF - * at least one character is in the range U+10000-U+10FFFF - */ - unsigned int kind:3; - /* Compact is with respect to the allocation scheme. Compact unicode - objects only require one memory block while non-compact objects use - one block for the PyUnicodeObject struct and another for its data - buffer. */ - unsigned int compact:1; - /* The string only contains characters in the range U+0000-U+007F (ASCII) - and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is - set, use the PyASCIIObject structure. */ - unsigned int ascii:1; - /* The ready flag indicates whether the object layout is initialized - completely. This means that this is either a compact object, or - the data pointer is filled out. The bit is redundant, and helps - to minimize the test in PyUnicode_IS_READY(). */ - unsigned int ready:1; - /* Padding to ensure that PyUnicode_DATA() is always aligned to - 4 bytes (see issue #19537 on m68k). */ - unsigned int :24; - } state; - wchar_t *wstr; /* wchar_t representation (null-terminated) */ -} PyASCIIObject; - -/* Non-ASCII strings allocated through PyUnicode_New use the - PyCompactUnicodeObject structure. state.compact is set, and the data - immediately follow the structure. */ -typedef struct { - PyASCIIObject _base; - Py_ssize_t utf8_length; /* Number of bytes in utf8, excluding the - * terminating \0. */ - char *utf8; /* UTF-8 representation (null-terminated) */ - Py_ssize_t wstr_length; /* Number of code points in wstr, possible - * surrogates count as two code points. */ -} PyCompactUnicodeObject; - -/* Strings allocated through PyUnicode_FromUnicode(NULL, len) use the - PyUnicodeObject structure. The actual string data is initially in the wstr - block, and copied into the data block using _PyUnicode_Ready. */ -typedef struct { - PyCompactUnicodeObject _base; - union { - void *any; - Py_UCS1 *latin1; - Py_UCS2 *ucs2; - Py_UCS4 *ucs4; - } data; /* Canonical, smallest-form Unicode buffer */ -} PyUnicodeObject; -#endif - -PyAPI_DATA(PyTypeObject) PyUnicode_Type; -PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type; - -#define PyUnicode_Check(op) \ - PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS) -#define PyUnicode_CheckExact(op) (Py_TYPE(op) == &PyUnicode_Type) - -/* Fast access macros */ -#ifndef Py_LIMITED_API - -#define PyUnicode_WSTR_LENGTH(op) \ - (PyUnicode_IS_COMPACT_ASCII(op) ? \ - ((PyASCIIObject*)op)->length : \ - ((PyCompactUnicodeObject*)op)->wstr_length) - -/* Returns the deprecated Py_UNICODE representation's size in code units - (this includes surrogate pairs as 2 units). - If the Py_UNICODE representation is not available, it will be computed - on request. Use PyUnicode_GET_LENGTH() for the length in code points. */ - -#define PyUnicode_GET_SIZE(op) \ - (assert(PyUnicode_Check(op)), \ - (((PyASCIIObject *)(op))->wstr) ? \ - PyUnicode_WSTR_LENGTH(op) : \ - ((void)PyUnicode_AsUnicode((PyObject *)(op)), \ - assert(((PyASCIIObject *)(op))->wstr), \ - PyUnicode_WSTR_LENGTH(op))) - -#define PyUnicode_GET_DATA_SIZE(op) \ - (PyUnicode_GET_SIZE(op) * Py_UNICODE_SIZE) - -/* Alias for PyUnicode_AsUnicode(). This will create a wchar_t/Py_UNICODE - representation on demand. Using this macro is very inefficient now, - try to port your code to use the new PyUnicode_*BYTE_DATA() macros or - use PyUnicode_WRITE() and PyUnicode_READ(). */ - -#define PyUnicode_AS_UNICODE(op) \ - (assert(PyUnicode_Check(op)), \ - (((PyASCIIObject *)(op))->wstr) ? (((PyASCIIObject *)(op))->wstr) : \ - PyUnicode_AsUnicode((PyObject *)(op))) - -#define PyUnicode_AS_DATA(op) \ - ((const char *)(PyUnicode_AS_UNICODE(op))) - - -/* --- Flexible String Representation Helper Macros (PEP 393) -------------- */ - -/* Values for PyASCIIObject.state: */ - -/* Interning state. */ -#define SSTATE_NOT_INTERNED 0 -#define SSTATE_INTERNED_MORTAL 1 -#define SSTATE_INTERNED_IMMORTAL 2 - -/* Return true if the string contains only ASCII characters, or 0 if not. The - string may be compact (PyUnicode_IS_COMPACT_ASCII) or not, but must be - ready. */ -#define PyUnicode_IS_ASCII(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject*)op)->state.ascii) - -/* Return true if the string is compact or 0 if not. - No type checks or Ready calls are performed. */ -#define PyUnicode_IS_COMPACT(op) \ - (((PyASCIIObject*)(op))->state.compact) - -/* Return true if the string is a compact ASCII string (use PyASCIIObject - structure), or 0 if not. No type checks or Ready calls are performed. */ -#define PyUnicode_IS_COMPACT_ASCII(op) \ - (((PyASCIIObject*)op)->state.ascii && PyUnicode_IS_COMPACT(op)) - -enum PyUnicode_Kind { -/* String contains only wstr byte characters. This is only possible - when the string was created with a legacy API and _PyUnicode_Ready() - has not been called yet. */ - PyUnicode_WCHAR_KIND = 0, -/* Return values of the PyUnicode_KIND() macro: */ - PyUnicode_1BYTE_KIND = 1, - PyUnicode_2BYTE_KIND = 2, - PyUnicode_4BYTE_KIND = 4 -}; - -/* Return pointers to the canonical representation cast to unsigned char, - Py_UCS2, or Py_UCS4 for direct character access. - No checks are performed, use PyUnicode_KIND() before to ensure - these will work correctly. */ - -#define PyUnicode_1BYTE_DATA(op) ((Py_UCS1*)PyUnicode_DATA(op)) -#define PyUnicode_2BYTE_DATA(op) ((Py_UCS2*)PyUnicode_DATA(op)) -#define PyUnicode_4BYTE_DATA(op) ((Py_UCS4*)PyUnicode_DATA(op)) - -/* Return one of the PyUnicode_*_KIND values defined above. */ -#define PyUnicode_KIND(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject *)(op))->state.kind) - -/* Return a void pointer to the raw unicode buffer. */ -#define _PyUnicode_COMPACT_DATA(op) \ - (PyUnicode_IS_ASCII(op) ? \ - ((void*)((PyASCIIObject*)(op) + 1)) : \ - ((void*)((PyCompactUnicodeObject*)(op) + 1))) - -#define _PyUnicode_NONCOMPACT_DATA(op) \ - (assert(((PyUnicodeObject*)(op))->data.any), \ - ((((PyUnicodeObject *)(op))->data.any))) - -#define PyUnicode_DATA(op) \ - (assert(PyUnicode_Check(op)), \ - PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \ - _PyUnicode_NONCOMPACT_DATA(op)) - -/* In the access macros below, "kind" may be evaluated more than once. - All other macro parameters are evaluated exactly once, so it is safe - to put side effects into them (such as increasing the index). */ - -/* Write into the canonical representation, this macro does not do any sanity - checks and is intended for usage in loops. The caller should cache the - kind and data pointers obtained from other macro calls. - index is the index in the string (starts at 0) and value is the new - code point value which should be written to that location. */ -#define PyUnicode_WRITE(kind, data, index, value) \ - do { \ - switch ((kind)) { \ - case PyUnicode_1BYTE_KIND: { \ - ((Py_UCS1 *)(data))[(index)] = (Py_UCS1)(value); \ - break; \ - } \ - case PyUnicode_2BYTE_KIND: { \ - ((Py_UCS2 *)(data))[(index)] = (Py_UCS2)(value); \ - break; \ - } \ - default: { \ - assert((kind) == PyUnicode_4BYTE_KIND); \ - ((Py_UCS4 *)(data))[(index)] = (Py_UCS4)(value); \ - } \ - } \ - } while (0) - -/* Read a code point from the string's canonical representation. No checks - or ready calls are performed. */ -#define PyUnicode_READ(kind, data, index) \ - ((Py_UCS4) \ - ((kind) == PyUnicode_1BYTE_KIND ? \ - ((const Py_UCS1 *)(data))[(index)] : \ - ((kind) == PyUnicode_2BYTE_KIND ? \ - ((const Py_UCS2 *)(data))[(index)] : \ - ((const Py_UCS4 *)(data))[(index)] \ - ) \ - )) - -/* PyUnicode_READ_CHAR() is less efficient than PyUnicode_READ() because it - calls PyUnicode_KIND() and might call it twice. For single reads, use - PyUnicode_READ_CHAR, for multiple consecutive reads callers should - cache kind and use PyUnicode_READ instead. */ -#define PyUnicode_READ_CHAR(unicode, index) \ - (assert(PyUnicode_Check(unicode)), \ - assert(PyUnicode_IS_READY(unicode)), \ - (Py_UCS4) \ - (PyUnicode_KIND((unicode)) == PyUnicode_1BYTE_KIND ? \ - ((const Py_UCS1 *)(PyUnicode_DATA((unicode))))[(index)] : \ - (PyUnicode_KIND((unicode)) == PyUnicode_2BYTE_KIND ? \ - ((const Py_UCS2 *)(PyUnicode_DATA((unicode))))[(index)] : \ - ((const Py_UCS4 *)(PyUnicode_DATA((unicode))))[(index)] \ - ) \ - )) - -/* Returns the length of the unicode string. The caller has to make sure that - the string has it's canonical representation set before calling - this macro. Call PyUnicode_(FAST_)Ready to ensure that. */ -#define PyUnicode_GET_LENGTH(op) \ - (assert(PyUnicode_Check(op)), \ - assert(PyUnicode_IS_READY(op)), \ - ((PyASCIIObject *)(op))->length) - - -/* Fast check to determine whether an object is ready. Equivalent to - PyUnicode_IS_COMPACT(op) || ((PyUnicodeObject*)(op))->data.any) */ - -#define PyUnicode_IS_READY(op) (((PyASCIIObject*)op)->state.ready) - -/* PyUnicode_READY() does less work than _PyUnicode_Ready() in the best - case. If the canonical representation is not yet set, it will still call - _PyUnicode_Ready(). - Returns 0 on success and -1 on errors. */ -#define PyUnicode_READY(op) \ - (assert(PyUnicode_Check(op)), \ - (PyUnicode_IS_READY(op) ? \ - 0 : _PyUnicode_Ready((PyObject *)(op)))) - -/* Return a maximum character value which is suitable for creating another - string based on op. This is always an approximation but more efficient - than iterating over the string. */ -#define PyUnicode_MAX_CHAR_VALUE(op) \ - (assert(PyUnicode_IS_READY(op)), \ - (PyUnicode_IS_ASCII(op) ? \ - (0x7f) : \ - (PyUnicode_KIND(op) == PyUnicode_1BYTE_KIND ? \ - (0xffU) : \ - (PyUnicode_KIND(op) == PyUnicode_2BYTE_KIND ? \ - (0xffffU) : \ - (0x10ffffU))))) - -#endif - -/* --- Constants ---------------------------------------------------------- */ - -/* This Unicode character will be used as replacement character during - decoding if the errors argument is set to "replace". Note: the - Unicode character U+FFFD is the official REPLACEMENT CHARACTER in - Unicode 3.0. */ - -#define Py_UNICODE_REPLACEMENT_CHARACTER ((Py_UCS4) 0xFFFD) - -/* === Public API ========================================================= */ - -/* --- Plain Py_UNICODE --------------------------------------------------- */ - -/* With PEP 393, this is the recommended way to allocate a new unicode object. - This function will allocate the object and its buffer in a single memory - block. Objects created using this function are not resizable. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_New( - Py_ssize_t size, /* Number of code points in the new string */ - Py_UCS4 maxchar /* maximum code point value in the string */ - ); -#endif - -/* Initializes the canonical string representation from the deprecated - wstr/Py_UNICODE representation. This function is used to convert Unicode - objects which were created using the old API to the new flexible format - introduced with PEP 393. - - Don't call this function directly, use the public PyUnicode_READY() macro - instead. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) _PyUnicode_Ready( - PyObject *unicode /* Unicode object */ - ); -#endif - -/* Get a copy of a Unicode string. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyUnicode_Copy( - PyObject *unicode - ); -#endif - -/* Copy character from one unicode object into another, this function performs - character conversion when necessary and falls back to memcpy() if possible. - - Fail if to is too small (smaller than *how_many* or smaller than - len(from)-from_start), or if kind(from[from_start:from_start+how_many]) > - kind(to), or if *to* has more than 1 reference. - - Return the number of written character, or return -1 and raise an exception - on error. - - Pseudo-code: - - how_many = min(how_many, len(from) - from_start) - to[to_start:to_start+how_many] = from[from_start:from_start+how_many] - return how_many - - Note: The function doesn't write a terminating null character. - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) PyUnicode_CopyCharacters( - PyObject *to, - Py_ssize_t to_start, - PyObject *from, - Py_ssize_t from_start, - Py_ssize_t how_many - ); - -/* Unsafe version of PyUnicode_CopyCharacters(): don't check arguments and so - may crash if parameters are invalid (e.g. if the output string - is too short). */ -PyAPI_FUNC(void) _PyUnicode_FastCopyCharacters( - PyObject *to, - Py_ssize_t to_start, - PyObject *from, - Py_ssize_t from_start, - Py_ssize_t how_many - ); -#endif - -#ifndef Py_LIMITED_API -/* Fill a string with a character: write fill_char into - unicode[start:start+length]. - - Fail if fill_char is bigger than the string maximum character, or if the - string has more than 1 reference. - - Return the number of written character, or return -1 and raise an exception - on error. */ -PyAPI_FUNC(Py_ssize_t) PyUnicode_Fill( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t length, - Py_UCS4 fill_char - ); - -/* Unsafe version of PyUnicode_Fill(): don't check arguments and so may crash - if parameters are invalid (e.g. if length is longer than the string). */ -PyAPI_FUNC(void) _PyUnicode_FastFill( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t length, - Py_UCS4 fill_char - ); -#endif - -/* Create a Unicode Object from the Py_UNICODE buffer u of the given - size. - - u may be NULL which causes the contents to be undefined. It is the - user's responsibility to fill in the needed data afterwards. Note - that modifying the Unicode object contents after construction is - only allowed if u was set to NULL. - - The buffer is copied into the new object. */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode( - const Py_UNICODE *u, /* Unicode buffer */ - Py_ssize_t size /* size of buffer */ - ); -#endif - -/* Similar to PyUnicode_FromUnicode(), but u points to UTF-8 encoded bytes */ -PyAPI_FUNC(PyObject*) PyUnicode_FromStringAndSize( - const char *u, /* UTF-8 encoded string */ - Py_ssize_t size /* size of buffer */ - ); - -/* Similar to PyUnicode_FromUnicode(), but u points to null-terminated - UTF-8 encoded bytes. The size is determined with strlen(). */ -PyAPI_FUNC(PyObject*) PyUnicode_FromString( - const char *u /* UTF-8 encoded string */ - ); - -#ifndef Py_LIMITED_API -/* Create a new string from a buffer of Py_UCS1, Py_UCS2 or Py_UCS4 characters. - Scan the string to find the maximum character. */ -PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData( - int kind, - const void *buffer, - Py_ssize_t size); - -/* Create a new string from a buffer of ASCII characters. - WARNING: Don't check if the string contains any non-ASCII character. */ -PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII( - const char *buffer, - Py_ssize_t size); -#endif - -PyAPI_FUNC(PyObject*) PyUnicode_Substring( - PyObject *str, - Py_ssize_t start, - Py_ssize_t end); - -#ifndef Py_LIMITED_API -/* Compute the maximum character of the substring unicode[start:end]. - Return 127 for an empty string. */ -PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t end); -#endif - -/* Copy the string into a UCS4 buffer including the null character if copy_null - is set. Return NULL and raise an exception on error. Raise a SystemError if - the buffer is smaller than the string. Return buffer on success. - - buflen is the length of the buffer in (Py_UCS4) characters. */ -PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4( - PyObject *unicode, - Py_UCS4* buffer, - Py_ssize_t buflen, - int copy_null); - -/* Copy the string into a UCS4 buffer. A new buffer is allocated using - * PyMem_Malloc; if this fails, NULL is returned with a memory error - exception set. */ -PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4Copy(PyObject *unicode); - -/* Return a read-only pointer to the Unicode object's internal - Py_UNICODE buffer. - If the wchar_t/Py_UNICODE representation is not yet available, this - function will calculate it. */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode( - PyObject *unicode /* Unicode object */ - ); -#endif - -/* Return a read-only pointer to the Unicode object's internal - Py_UNICODE buffer and save the length at size. - If the wchar_t/Py_UNICODE representation is not yet available, this - function will calculate it. */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicodeAndSize( - PyObject *unicode, /* Unicode object */ - Py_ssize_t *size /* location where to save the length */ - ); -#endif - -/* Get the length of the Unicode object. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_GetLength( - PyObject *unicode -); - -/* Get the number of Py_UNICODE units in the - string representation. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_GetSize( - PyObject *unicode /* Unicode object */ - ); - -/* Read a character from the string. */ - -PyAPI_FUNC(Py_UCS4) PyUnicode_ReadChar( - PyObject *unicode, - Py_ssize_t index - ); - -/* Write a character to the string. The string must have been created through - PyUnicode_New, must not be shared, and must not have been hashed yet. - - Return 0 on success, -1 on error. */ - -PyAPI_FUNC(int) PyUnicode_WriteChar( - PyObject *unicode, - Py_ssize_t index, - Py_UCS4 character - ); - -#ifndef Py_LIMITED_API -/* Get the maximum ordinal for a Unicode character. */ -PyAPI_FUNC(Py_UNICODE) PyUnicode_GetMax(void); -#endif - -/* Resize a Unicode object. The length is the number of characters, except - if the kind of the string is PyUnicode_WCHAR_KIND: in this case, the length - is the number of Py_UNICODE characters. - - *unicode is modified to point to the new (resized) object and 0 - returned on success. - - Try to resize the string in place (which is usually faster than allocating - a new string and copy characters), or create a new string. - - Error handling is implemented as follows: an exception is set, -1 - is returned and *unicode left untouched. - - WARNING: The function doesn't check string content, the result may not be a - string in canonical representation. */ - -PyAPI_FUNC(int) PyUnicode_Resize( - PyObject **unicode, /* Pointer to the Unicode object */ - Py_ssize_t length /* New length */ - ); - -/* Decode obj to a Unicode object. - - bytes, bytearray and other bytes-like objects are decoded according to the - given encoding and error handler. The encoding and error handler can be - NULL to have the interface use UTF-8 and "strict". - - All other objects (including Unicode objects) raise an exception. - - The API returns NULL in case of an error. The caller is responsible - for decref'ing the returned objects. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromEncodedObject( - PyObject *obj, /* Object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Copy an instance of a Unicode subtype to a new true Unicode object if - necessary. If obj is already a true Unicode object (not a subtype), return - the reference with *incremented* refcount. - - The API returns NULL in case of an error. The caller is responsible - for decref'ing the returned objects. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromObject( - PyObject *obj /* Object */ - ); - -PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV( - const char *format, /* ASCII-encoded string */ - va_list vargs - ); -PyAPI_FUNC(PyObject *) PyUnicode_FromFormat( - const char *format, /* ASCII-encoded string */ - ... - ); - -#ifndef Py_LIMITED_API -typedef struct { - PyObject *buffer; - void *data; - enum PyUnicode_Kind kind; - Py_UCS4 maxchar; - Py_ssize_t size; - Py_ssize_t pos; - - /* minimum number of allocated characters (default: 0) */ - Py_ssize_t min_length; - - /* minimum character (default: 127, ASCII) */ - Py_UCS4 min_char; - - /* If non-zero, overallocate the buffer by 25% (default: 0). */ - unsigned char overallocate; - - /* If readonly is 1, buffer is a shared string (cannot be modified) - and size is set to 0. */ - unsigned char readonly; -} _PyUnicodeWriter ; - -/* Initialize a Unicode writer. - * - * By default, the minimum buffer size is 0 character and overallocation is - * disabled. Set min_length, min_char and overallocate attributes to control - * the allocation of the buffer. */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Init(_PyUnicodeWriter *writer); - -/* Prepare the buffer to write 'length' characters - with the specified maximum character. - - Return 0 on success, raise an exception and return -1 on error. */ -#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \ - (((MAXCHAR) <= (WRITER)->maxchar \ - && (LENGTH) <= (WRITER)->size - (WRITER)->pos) \ - ? 0 \ - : (((LENGTH) == 0) \ - ? 0 \ - : _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR)))) - -/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro - instead. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, - Py_ssize_t length, Py_UCS4 maxchar); - -/* Append a Unicode character. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, - Py_UCS4 ch - ); - -/* Append a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, - PyObject *str /* Unicode string */ - ); - -/* Append a substring of a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, - PyObject *str, /* Unicode string */ - Py_ssize_t start, - Py_ssize_t end - ); - -/* Append an ASCII-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, - const char *str, /* ASCII-encoded byte string */ - Py_ssize_t len /* number of bytes, or -1 if unknown */ - ); - -/* Append a latin1-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, - const char *str, /* latin1-encoded byte string */ - Py_ssize_t len /* length in bytes */ - ); - -/* Get the value of the writer as a Unicode string. Clear the - buffer of the writer. Raise an exception and return NULL - on error. */ -PyAPI_FUNC(PyObject *) -_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); -#endif - -#ifndef Py_LIMITED_API -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif - -PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **); -PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); -PyAPI_FUNC(PyObject *) PyUnicode_InternFromString( - const char *u /* UTF-8 encoded string */ - ); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_ReleaseInternedUnicodeStrings(void); -#endif - -/* Use only if you know it's a string */ -#define PyUnicode_CHECK_INTERNED(op) \ - (((PyASCIIObject *)(op))->state.interned) - -/* --- wchar_t support for platforms which support it --------------------- */ - -#ifdef HAVE_WCHAR_H - -/* Create a Unicode Object from the wchar_t buffer w of the given - size. - - The buffer is copied into the new object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_FromWideChar( - const wchar_t *w, /* wchar_t buffer */ - Py_ssize_t size /* size of buffer */ - ); - -/* Copies the Unicode Object contents into the wchar_t buffer w. At - most size wchar_t characters are copied. - - Note that the resulting wchar_t string may or may not be - 0-terminated. It is the responsibility of the caller to make sure - that the wchar_t string is 0-terminated in case this is required by - the application. - - Returns the number of wchar_t characters copied (excluding a - possibly trailing 0-termination character) or -1 in case of an - error. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_AsWideChar( - PyObject *unicode, /* Unicode object */ - wchar_t *w, /* wchar_t buffer */ - Py_ssize_t size /* size of buffer */ - ); - -/* Convert the Unicode object to a wide character string. The output string - always ends with a nul character. If size is not NULL, write the number of - wide characters (excluding the null character) into *size. - - Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) - on success. On error, returns NULL, *size is undefined and raises a - MemoryError. */ - -PyAPI_FUNC(wchar_t*) PyUnicode_AsWideCharString( - PyObject *unicode, /* Unicode object */ - Py_ssize_t *size /* number of characters of the result */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(void*) _PyUnicode_AsKind(PyObject *s, unsigned int kind); -#endif - -#endif - -/* --- Unicode ordinals --------------------------------------------------- */ - -/* Create a Unicode Object from the given Unicode code point ordinal. - - The ordinal must be in range(0x110000). A ValueError is - raised in case it is not. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_FromOrdinal(int ordinal); - -/* --- Free-list management ----------------------------------------------- */ - -/* Clear the free list used by the Unicode implementation. - - This can be used to release memory used for objects on the free - list back to the Python memory allocator. - -*/ - -PyAPI_FUNC(int) PyUnicode_ClearFreeList(void); - -/* === Builtin Codecs ===================================================== - - Many of these APIs take two arguments encoding and errors. These - parameters encoding and errors have the same semantics as the ones - of the builtin str() API. - - Setting encoding to NULL causes the default encoding (UTF-8) to be used. - - Error handling is set by errors which may also be set to NULL - meaning to use the default handling defined for the codec. Default - error handling for all builtin codecs is "strict" (ValueErrors are - raised). - - The codecs all use a similar interface. Only deviation from the - generic ones are documented. - -*/ - -/* --- Manage the default encoding ---------------------------------------- */ - -/* Returns a pointer to the default encoding (UTF-8) of the - Unicode object unicode and the size of the encoded representation - in bytes stored in *size. - - In case of an error, no *size is set. - - This function caches the UTF-8 encoded string in the unicodeobject - and subsequent calls will return the same string. The memory is released - when the unicodeobject is deallocated. - - _PyUnicode_AsStringAndSize is a #define for PyUnicode_AsUTF8AndSize to - support the previous internal function with the same behaviour. - - *** This API is for interpreter INTERNAL USE ONLY and will likely - *** be removed or changed in the future. - - *** If you need to access the Unicode object as UTF-8 bytes string, - *** please use PyUnicode_AsUTF8String() instead. -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) PyUnicode_AsUTF8AndSize( - PyObject *unicode, - Py_ssize_t *size); -#define _PyUnicode_AsStringAndSize PyUnicode_AsUTF8AndSize -#endif - -/* Returns a pointer to the default encoding (UTF-8) of the - Unicode object unicode. - - Like PyUnicode_AsUTF8AndSize(), this also caches the UTF-8 representation - in the unicodeobject. - - _PyUnicode_AsString is a #define for PyUnicode_AsUTF8 to - support the previous internal function with the same behaviour. - - Use of this API is DEPRECATED since no size information can be - extracted from the returned data. - - *** This API is for interpreter INTERNAL USE ONLY and will likely - *** be removed or changed for Python 3.1. - - *** If you need to access the Unicode object as UTF-8 bytes string, - *** please use PyUnicode_AsUTF8String() instead. - -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(char *) PyUnicode_AsUTF8(PyObject *unicode); -#define _PyUnicode_AsString PyUnicode_AsUTF8 -#endif - -/* Returns "utf-8". */ - -PyAPI_FUNC(const char*) PyUnicode_GetDefaultEncoding(void); - -/* --- Generic Codecs ----------------------------------------------------- */ - -/* Create a Unicode object by decoding the encoded string s of the - given size. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Decode( - const char *s, /* encoded string */ - Py_ssize_t size, /* size of buffer */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Decode a Unicode object unicode and return the result as Python - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedObject( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Decode a Unicode object unicode and return the result as Unicode - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedUnicode( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Py_UNICODE buffer of the given size and returns a - Python string object. */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_Encode( - const Py_UNICODE *s, /* Unicode char buffer */ - Py_ssize_t size, /* number of Py_UNICODE chars to encode */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); -#endif - -/* Encodes a Unicode object and returns the result as Python - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Unicode object and returns the result as Python string - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedString( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Encodes a Unicode object and returns the result as Unicode - object. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedUnicode( - PyObject *unicode, /* Unicode object */ - const char *encoding, /* encoding */ - const char *errors /* error handling */ - ); - -/* Build an encoding map. */ - -PyAPI_FUNC(PyObject*) PyUnicode_BuildEncodingMap( - PyObject* string /* 256 character map */ - ); - -/* --- UTF-7 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7( - const char *string, /* UTF-7 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7Stateful( - const char *string, /* UTF-7 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF7( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ - const char *errors /* error handling */ - ); -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF7( - PyObject *unicode, /* Unicode object */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ - const char *errors /* error handling */ - ); -#endif - -/* --- UTF-8 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8( - const char *string, /* UTF-8 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8Stateful( - const char *string, /* UTF-8 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF8String( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyUnicode_AsUTF8String( - PyObject *unicode, - const char *errors); - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF8( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); -#endif - -/* --- UTF-32 Codecs ------------------------------------------------------ */ - -/* Decodes length bytes from a UTF-32 encoded buffer string and returns - the corresponding Unicode object. - - errors (if non-NULL) defines the error handling. It defaults - to "strict". - - If byteorder is non-NULL, the decoder starts decoding using the - given byte order: - - *byteorder == -1: little endian - *byteorder == 0: native order - *byteorder == 1: big endian - - In native mode, the first four bytes of the stream are checked for a - BOM mark. If found, the BOM mark is analysed, the byte order - adjusted and the BOM skipped. In the other modes, no BOM mark - interpretation is done. After completion, *byteorder is set to the - current byte order at the end of input data. - - If byteorder is NULL, the codec starts in native order mode. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32( - const char *string, /* UTF-32 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32Stateful( - const char *string, /* UTF-32 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder, /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -/* Returns a Python string using the UTF-32 encoding in native byte - order. The string always starts with a BOM mark. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF32String( - PyObject *unicode /* Unicode object */ - ); - -/* Returns a Python string object holding the UTF-32 encoded value of - the Unicode data. - - If byteorder is not 0, output is written according to the following - byte order: - - byteorder == -1: little endian - byteorder == 0: native byte order (writes a BOM mark) - byteorder == 1: big endian - - If byteorder is 0, the output string will always start with the - Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is - prepended. - -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF32( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF32( - PyObject *object, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); -#endif - -/* --- UTF-16 Codecs ------------------------------------------------------ */ - -/* Decodes length bytes from a UTF-16 encoded buffer string and returns - the corresponding Unicode object. - - errors (if non-NULL) defines the error handling. It defaults - to "strict". - - If byteorder is non-NULL, the decoder starts decoding using the - given byte order: - - *byteorder == -1: little endian - *byteorder == 0: native order - *byteorder == 1: big endian - - In native mode, the first two bytes of the stream are checked for a - BOM mark. If found, the BOM mark is analysed, the byte order - adjusted and the BOM skipped. In the other modes, no BOM mark - interpretation is done. After completion, *byteorder is set to the - current byte order at the end of input data. - - If byteorder is NULL, the codec starts in native order mode. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16( - const char *string, /* UTF-16 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16Stateful( - const char *string, /* UTF-16 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - int *byteorder, /* pointer to byteorder to use - 0=native;-1=LE,1=BE; updated on - exit */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -/* Returns a Python string using the UTF-16 encoding in native byte - order. The string always starts with a BOM mark. */ - -PyAPI_FUNC(PyObject*) PyUnicode_AsUTF16String( - PyObject *unicode /* Unicode object */ - ); - -/* Returns a Python string object holding the UTF-16 encoded value of - the Unicode data. - - If byteorder is not 0, output is written according to the following - byte order: - - byteorder == -1: little endian - byteorder == 0: native byte order (writes a BOM mark) - byteorder == 1: big endian - - If byteorder is 0, the output string will always start with the - Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is - prepended. - - Note that Py_UNICODE data is being interpreted as UTF-16 reduced to - UCS-2. This trick makes it possible to add full UTF-16 capabilities - at a later point without compromising the APIs. - -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF16( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF16( - PyObject* unicode, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); -#endif - -/* --- Unicode-Escape Codecs ---------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeUnicodeEscape( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeUnicodeEscape( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to encode */ - ); -#endif - -/* --- Raw-Unicode-Escape Codecs ------------------------------------------ */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeRawUnicodeEscape( - const char *string, /* Raw-Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsRawUnicodeEscapeString( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeRawUnicodeEscape( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to encode */ - ); -#endif - -/* --- Unicode Internal Codec --------------------------------------------- - - Only for internal use in _codecsmodule.c */ - -#ifndef Py_LIMITED_API -PyObject *_PyUnicode_DecodeUnicodeInternal( - const char *string, - Py_ssize_t length, - const char *errors - ); -#endif - -/* --- Latin-1 Codecs ----------------------------------------------------- - - Note: Latin-1 corresponds to the first 256 Unicode ordinals. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLatin1( - const char *string, /* Latin-1 encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsLatin1String( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyUnicode_AsLatin1String( - PyObject* unicode, - const char* errors); - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeLatin1( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); -#endif - -/* --- ASCII Codecs ------------------------------------------------------- - - Only 7-bit ASCII data is excepted. All other codes generate errors. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeASCII( - const char *string, /* ASCII encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsASCIIString( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyUnicode_AsASCIIString( - PyObject* unicode, - const char* errors); - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeASCII( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); -#endif - -/* --- Character Map Codecs ----------------------------------------------- - - This codec uses mappings to encode and decode characters. - - Decoding mappings must map single string characters to single - Unicode characters, integers (which are then interpreted as Unicode - ordinals) or None (meaning "undefined mapping" and causing an - error). - - Encoding mappings must map single Unicode characters to single - string characters, integers (which are then interpreted as Latin-1 - ordinals) or None (meaning "undefined mapping" and causing an - error). - - If a character lookup fails with a LookupError, the character is - copied as-is meaning that its ordinal value will be interpreted as - Unicode or Latin-1 ordinal resp. Because of this mappings only need - to contain those mappings which map characters to different code - points. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeCharmap( - const char *string, /* Encoded string */ - Py_ssize_t length, /* size of string */ - PyObject *mapping, /* character mapping - (char ordinal -> unicode ordinal) */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsCharmapString( - PyObject *unicode, /* Unicode object */ - PyObject *mapping /* character mapping - (unicode ordinal -> char ordinal) */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - PyObject *mapping, /* character mapping - (unicode ordinal -> char ordinal) */ - const char *errors /* error handling */ - ); -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeCharmap( - PyObject *unicode, /* Unicode object */ - PyObject *mapping, /* character mapping - (unicode ordinal -> char ordinal) */ - const char *errors /* error handling */ - ); -#endif - -/* Translate a Py_UNICODE buffer of the given length by applying a - character mapping table to it and return the resulting Unicode - object. - - The mapping table must map Unicode ordinal integers to Unicode - ordinal integers or None (causing deletion of the character). - - Mapping tables may be dictionaries or sequences. Unmapped character - ordinals (ones which cause a LookupError) are left untouched and - are copied as-is. - -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) PyUnicode_TranslateCharmap( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - PyObject *table, /* Translate table */ - const char *errors /* error handling */ - ); -#endif - -#ifdef HAVE_MBCS - -/* --- MBCS codecs for Windows -------------------------------------------- */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCS( - const char *string, /* MBCS encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors /* error handling */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCSStateful( - const char *string, /* MBCS encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeCodePageStateful( - int code_page, /* code page number */ - const char *string, /* encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ - ); - -PyAPI_FUNC(PyObject*) PyUnicode_AsMBCSString( - PyObject *unicode /* Unicode object */ - ); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_EncodeMBCS( - const Py_UNICODE *data, /* Unicode char buffer */ - Py_ssize_t length, /* number of Py_UNICODE chars to encode */ - const char *errors /* error handling */ - ); -#endif - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeCodePage( - int code_page, /* code page number */ - PyObject *unicode, /* Unicode object */ - const char *errors /* error handling */ - ); - -#endif /* HAVE_MBCS */ - -/* --- Decimal Encoder ---------------------------------------------------- */ - -/* Takes a Unicode string holding a decimal value and writes it into - an output buffer using standard ASCII digit codes. - - The output buffer has to provide at least length+1 bytes of storage - area. The output string is 0-terminated. - - The encoder converts whitespace to ' ', decimal characters to their - corresponding ASCII digit and all other Latin-1 characters except - \0 as-is. Characters outside this range (Unicode ordinals 1-256) - are treated as errors. This includes embedded NULL bytes. - - Error handling is defined by the errors argument: - - NULL or "strict": raise a ValueError - "ignore": ignore the wrong characters (these are not copied to the - output buffer) - "replace": replaces illegal characters with '?' - - Returns 0 on success, -1 on failure. - -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyUnicode_EncodeDecimal( - Py_UNICODE *s, /* Unicode buffer */ - Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ - char *output, /* Output buffer; must have size >= length */ - const char *errors /* error handling */ - ); -#endif - -/* Transforms code points that have decimal digit property to the - corresponding ASCII digit code points. - - Returns a new Unicode string on success, NULL on failure. -*/ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) PyUnicode_TransformDecimalToASCII( - Py_UNICODE *s, /* Unicode buffer */ - Py_ssize_t length /* Number of Py_UNICODE chars to transform */ - ); -#endif - -/* Similar to PyUnicode_TransformDecimalToASCII(), but takes a PyObject - as argument instead of a raw buffer and length. This function additionally - transforms spaces to ASCII because this is what the callers in longobject, - floatobject, and complexobject did anyways. */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( - PyObject *unicode /* Unicode object */ - ); -#endif - -/* --- Locale encoding --------------------------------------------------- */ - -/* Decode a string from the current locale encoding. The decoder is strict if - *surrogateescape* is equal to zero, otherwise it uses the 'surrogateescape' - error handler (PEP 383) to escape undecodable bytes. If a byte sequence can - be decoded as a surrogate character and *surrogateescape* is not equal to - zero, the byte sequence is escaped using the 'surrogateescape' error handler - instead of being decoded. *str* must end with a null character but cannot - contain embedded null characters. */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocaleAndSize( - const char *str, - Py_ssize_t len, - const char *errors); - -/* Similar to PyUnicode_DecodeLocaleAndSize(), but compute the string - length using strlen(). */ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocale( - const char *str, - const char *errors); - -/* Encode a Unicode object to the current locale encoding. The encoder is - strict is *surrogateescape* is equal to zero, otherwise the - "surrogateescape" error handler is used. Return a bytes object. The string - cannot contain embedded null characters. */ - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeLocale( - PyObject *unicode, - const char *errors - ); - -/* --- File system encoding ---------------------------------------------- */ - -/* ParseTuple converter: encode str objects to bytes using - PyUnicode_EncodeFSDefault(); bytes objects are output as-is. */ - -PyAPI_FUNC(int) PyUnicode_FSConverter(PyObject*, void*); - -/* ParseTuple converter: decode bytes objects to unicode using - PyUnicode_DecodeFSDefaultAndSize(); str objects are output as-is. */ - -PyAPI_FUNC(int) PyUnicode_FSDecoder(PyObject*, void*); - -/* Decode a null-terminated string using Py_FileSystemDefaultEncoding - and the "surrogateescape" error handler. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. - - Use PyUnicode_DecodeFSDefaultAndSize() if the string length is known. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefault( - const char *s /* encoded string */ - ); - -/* Decode a string using Py_FileSystemDefaultEncoding - and the "surrogateescape" error handler. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefaultAndSize( - const char *s, /* encoded string */ - Py_ssize_t size /* size */ - ); - -/* Encode a Unicode object to Py_FileSystemDefaultEncoding with the - "surrogateescape" error handler, and return bytes. - - If Py_FileSystemDefaultEncoding is not set, fall back to the locale - encoding. -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_EncodeFSDefault( - PyObject *unicode - ); - -/* --- Methods & Slots ---------------------------------------------------- - - These are capable of handling Unicode objects and strings on input - (we refer to them as strings in the descriptions) and return - Unicode objects or integers as appropriate. */ - -/* Concat two strings giving a new Unicode string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Concat( - PyObject *left, /* Left string */ - PyObject *right /* Right string */ - ); - -/* Concat two strings and put the result in *pleft - (sets *pleft to NULL on error) */ - -PyAPI_FUNC(void) PyUnicode_Append( - PyObject **pleft, /* Pointer to left string */ - PyObject *right /* Right string */ - ); - -/* Concat two strings, put the result in *pleft and drop the right object - (sets *pleft to NULL on error) */ - -PyAPI_FUNC(void) PyUnicode_AppendAndDel( - PyObject **pleft, /* Pointer to left string */ - PyObject *right /* Right string */ - ); - -/* Split a string giving a list of Unicode strings. - - If sep is NULL, splitting will be done at all whitespace - substrings. Otherwise, splits occur at the given separator. - - At most maxsplit splits will be done. If negative, no limit is set. - - Separators are not included in the resulting list. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_Split( - PyObject *s, /* String to split */ - PyObject *sep, /* String separator */ - Py_ssize_t maxsplit /* Maxsplit count */ - ); - -/* Dito, but split at line breaks. - - CRLF is considered to be one line break. Line breaks are not - included in the resulting list. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Splitlines( - PyObject *s, /* String to split */ - int keepends /* If true, line end markers are included */ - ); - -/* Partition a string using a given separator. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Partition( - PyObject *s, /* String to partition */ - PyObject *sep /* String separator */ - ); - -/* Partition a string using a given separator, searching from the end of the - string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_RPartition( - PyObject *s, /* String to partition */ - PyObject *sep /* String separator */ - ); - -/* Split a string giving a list of Unicode strings. - - If sep is NULL, splitting will be done at all whitespace - substrings. Otherwise, splits occur at the given separator. - - At most maxsplit splits will be done. But unlike PyUnicode_Split - PyUnicode_RSplit splits from the end of the string. If negative, - no limit is set. - - Separators are not included in the resulting list. - -*/ - -PyAPI_FUNC(PyObject*) PyUnicode_RSplit( - PyObject *s, /* String to split */ - PyObject *sep, /* String separator */ - Py_ssize_t maxsplit /* Maxsplit count */ - ); - -/* Translate a string by applying a character mapping table to it and - return the resulting Unicode object. - - The mapping table must map Unicode ordinal integers to Unicode - ordinal integers or None (causing deletion of the character). - - Mapping tables may be dictionaries or sequences. Unmapped character - ordinals (ones which cause a LookupError) are left untouched and - are copied as-is. - -*/ - -PyAPI_FUNC(PyObject *) PyUnicode_Translate( - PyObject *str, /* String */ - PyObject *table, /* Translate table */ - const char *errors /* error handling */ - ); - -/* Join a sequence of strings using the given separator and return - the resulting Unicode string. */ - -PyAPI_FUNC(PyObject*) PyUnicode_Join( - PyObject *separator, /* Separator string */ - PyObject *seq /* Sequence object */ - ); - -/* Return 1 if substr matches str[start:end] at the given tail end, 0 - otherwise. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Tailmatch( - PyObject *str, /* String */ - PyObject *substr, /* Prefix or Suffix string */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end, /* Stop index */ - int direction /* Tail end: -1 prefix, +1 suffix */ - ); - -/* Return the first position of substr in str[start:end] using the - given search direction or -1 if not found. -2 is returned in case - an error occurred and an exception is set. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Find( - PyObject *str, /* String */ - PyObject *substr, /* Substring to find */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end, /* Stop index */ - int direction /* Find direction: +1 forward, -1 backward */ - ); - -/* Like PyUnicode_Find, but search for single character only. */ -PyAPI_FUNC(Py_ssize_t) PyUnicode_FindChar( - PyObject *str, - Py_UCS4 ch, - Py_ssize_t start, - Py_ssize_t end, - int direction - ); - -/* Count the number of occurrences of substr in str[start:end]. */ - -PyAPI_FUNC(Py_ssize_t) PyUnicode_Count( - PyObject *str, /* String */ - PyObject *substr, /* Substring to count */ - Py_ssize_t start, /* Start index */ - Py_ssize_t end /* Stop index */ - ); - -/* Replace at most maxcount occurrences of substr in str with replstr - and return the resulting Unicode object. */ - -PyAPI_FUNC(PyObject *) PyUnicode_Replace( - PyObject *str, /* String */ - PyObject *substr, /* Substring to find */ - PyObject *replstr, /* Substring to replace */ - Py_ssize_t maxcount /* Max. number of replacements to apply; - -1 = all */ - ); - -/* Compare two strings and return -1, 0, 1 for less than, equal, - greater than resp. - Raise an exception and return -1 on error. */ - -PyAPI_FUNC(int) PyUnicode_Compare( - PyObject *left, /* Left string */ - PyObject *right /* Right string */ - ); - -#ifndef Py_LIMITED_API -/* Compare a string with an identifier and return -1, 0, 1 for less than, - equal, and greater than, respectively. - Raise an exception and return -1 on error. */ - -PyAPI_FUNC(int) _PyUnicode_CompareWithId( - PyObject *left, /* Left string */ - _Py_Identifier *right /* Right identifier */ - ); - -/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, - 0 otherwise. Return 0 if any argument contains non-ASCII characters. - Any error occurs inside will be cleared before return. */ - -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIId( - PyObject *left, /* Left string */ - _Py_Identifier *right /* Right identifier */ - ); -#endif - -/* Compare a Unicode object with C string and return -1, 0, 1 for less than, - equal, and greater than, respectively. It is best to pass only - ASCII-encoded strings, but the function interprets the input string as - ISO-8859-1 if it contains non-ASCII characters. - This function does not raise exceptions. */ - -PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString( - PyObject *left, - const char *right /* ASCII-encoded string */ - ); - -#ifndef Py_LIMITED_API -/* Test whether a unicode is equal to ASCII string. Return 1 if true, - 0 otherwise. Return 0 if any argument contains non-ASCII characters. - Any error occurs inside will be cleared before return. */ - -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIString( - PyObject *left, - const char *right /* ASCII-encoded string */ - ); -#endif - -/* Rich compare two strings and return one of the following: - - - NULL in case an exception was raised - - Py_True or Py_False for successful comparisons - - Py_NotImplemented in case the type combination is unknown - - Possible values for op: - - Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE - -*/ - -PyAPI_FUNC(PyObject *) PyUnicode_RichCompare( - PyObject *left, /* Left string */ - PyObject *right, /* Right string */ - int op /* Operation: Py_EQ, Py_NE, Py_GT, etc. */ - ); - -/* Apply an argument tuple or dictionary to a format string and return - the resulting Unicode string. */ - -PyAPI_FUNC(PyObject *) PyUnicode_Format( - PyObject *format, /* Format string */ - PyObject *args /* Argument tuple or dictionary */ - ); - -/* Checks whether element is contained in container and return 1/0 - accordingly. - - element has to coerce to a one element Unicode string. -1 is - returned in case of an error. */ - -PyAPI_FUNC(int) PyUnicode_Contains( - PyObject *container, /* Container string */ - PyObject *element /* Element string */ - ); - -/* Checks whether argument is a valid identifier. */ - -PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s); - -#ifndef Py_LIMITED_API -/* Externally visible for str.strip(unicode) */ -PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( - PyObject *self, - int striptype, - PyObject *sepobj - ); -#endif - -/* Using explicit passed-in values, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( - PyObject *unicode, - Py_ssize_t index, - Py_ssize_t n_buffer, - void *digits, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - PyObject *thousands_sep, - Py_UCS4 *maxchar); -#endif -/* === Characters Type APIs =============================================== */ - -/* Helper array used by Py_UNICODE_ISSPACE(). */ - -#ifndef Py_LIMITED_API -PyAPI_DATA(const unsigned char) _Py_ascii_whitespace[]; - -/* These should not be used directly. Use the Py_UNICODE_IS* and - Py_UNICODE_TO* macros instead. - - These APIs are implemented in Objects/unicodectype.c. - -*/ - -PyAPI_FUNC(int) _PyUnicode_IsLowercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsUppercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsTitlecase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsXidStart( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsXidContinue( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsWhitespace( - const Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsLinebreak( - const Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(Py_UCS4) _PyUnicode_ToLowercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(Py_UCS4) _PyUnicode_ToUppercase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(Py_UCS4) _PyUnicode_ToTitlecase( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToLowerFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToTitleFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToUpperFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_ToFoldedFull( - Py_UCS4 ch, /* Unicode character */ - Py_UCS4 *res - ); - -PyAPI_FUNC(int) _PyUnicode_IsCaseIgnorable( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsCased( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToDecimalDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_ToDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(double) _PyUnicode_ToNumeric( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsDecimalDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsDigit( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsNumeric( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsPrintable( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(int) _PyUnicode_IsAlpha( - Py_UCS4 ch /* Unicode character */ - ); - -PyAPI_FUNC(size_t) Py_UNICODE_strlen( - const Py_UNICODE *u - ); - -PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcpy( - Py_UNICODE *s1, - const Py_UNICODE *s2); - -PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcat( - Py_UNICODE *s1, const Py_UNICODE *s2); - -PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strncpy( - Py_UNICODE *s1, - const Py_UNICODE *s2, - size_t n); - -PyAPI_FUNC(int) Py_UNICODE_strcmp( - const Py_UNICODE *s1, - const Py_UNICODE *s2 - ); - -PyAPI_FUNC(int) Py_UNICODE_strncmp( - const Py_UNICODE *s1, - const Py_UNICODE *s2, - size_t n - ); - -PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strchr( - const Py_UNICODE *s, - Py_UNICODE c - ); - -PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strrchr( - const Py_UNICODE *s, - Py_UNICODE c - ); - -PyAPI_FUNC(PyObject*) _PyUnicode_FormatLong(PyObject *, int, int, int); - -/* Create a copy of a unicode string ending with a nul character. Return NULL - and raise a MemoryError exception on memory allocation failure, otherwise - return a new allocated buffer (use PyMem_Free() to free the buffer). */ - -PyAPI_FUNC(Py_UNICODE*) PyUnicode_AsUnicodeCopy( - PyObject *unicode - ); -#endif /* Py_LIMITED_API */ - -#if defined(Py_DEBUG) && !defined(Py_LIMITED_API) -PyAPI_FUNC(int) _PyUnicode_CheckConsistency( - PyObject *op, - int check_content); -#endif - -/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/ -PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); -/* Clear all static strings. */ -PyAPI_FUNC(void) _PyUnicode_ClearStaticStrings(void); - -#ifdef __cplusplus -} -#endif -#endif /* !Py_UNICODEOBJECT_H */ +#ifndef Py_UNICODEOBJECT_H +#define Py_UNICODEOBJECT_H + +#include + +/* + +Unicode implementation based on original code by Fredrik Lundh, +modified by Marc-Andre Lemburg (mal@lemburg.com) according to the +Unicode Integration Proposal. (See +http://www.egenix.com/files/python/unicode-proposal.txt). + +Copyright (c) Corporation for National Research Initiatives. + + + Original header: + -------------------------------------------------------------------- + + * Yet another Unicode string type for Python. This type supports the + * 16-bit Basic Multilingual Plane (BMP) only. + * + * Written by Fredrik Lundh, January 1999. + * + * Copyright (c) 1999 by Secret Labs AB. + * Copyright (c) 1999 by Fredrik Lundh. + * + * fredrik@pythonware.com + * http://www.pythonware.com + * + * -------------------------------------------------------------------- + * This Unicode String Type is + * + * Copyright (c) 1999 by Secret Labs AB + * Copyright (c) 1999 by Fredrik Lundh + * + * By obtaining, using, and/or copying this software and/or its + * associated documentation, you agree that you have read, understood, + * and will comply with the following terms and conditions: + * + * Permission to use, copy, modify, and distribute this software and its + * associated documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appears in all + * copies, and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Secret Labs + * AB or the author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * -------------------------------------------------------------------- */ + +#include + +/* === Internal API ======================================================= */ + +/* --- Internal Unicode Format -------------------------------------------- */ + +/* Python 3.x requires unicode */ +#define Py_USING_UNICODE + +#ifndef SIZEOF_WCHAR_T +#error Must define SIZEOF_WCHAR_T +#endif + +#define Py_UNICODE_SIZE SIZEOF_WCHAR_T + +/* If wchar_t can be used for UCS-4 storage, set Py_UNICODE_WIDE. + Otherwise, Unicode strings are stored as UCS-2 (with limited support + for UTF-16) */ + +#if Py_UNICODE_SIZE >= 4 +#define Py_UNICODE_WIDE +#endif + +/* Set these flags if the platform has "wchar.h" and the + wchar_t type is a 16-bit unsigned type */ +/* #define HAVE_WCHAR_H */ +/* #define HAVE_USABLE_WCHAR_T */ + +/* Py_UNICODE was the native Unicode storage format (code unit) used by + Python and represents a single Unicode element in the Unicode type. + With PEP 393, Py_UNICODE is deprecated and replaced with a + typedef to wchar_t. */ + +#ifndef Py_LIMITED_API +#define PY_UNICODE_TYPE wchar_t +typedef wchar_t Py_UNICODE; +#endif + +/* If the compiler provides a wchar_t type we try to support it + through the interface functions PyUnicode_FromWideChar(), + PyUnicode_AsWideChar() and PyUnicode_AsWideCharString(). */ + +#ifdef HAVE_USABLE_WCHAR_T +# ifndef HAVE_WCHAR_H +# define HAVE_WCHAR_H +# endif +#endif + +#if defined(MS_WINDOWS) +# define HAVE_MBCS +#endif + +#ifdef HAVE_WCHAR_H +/* Work around a cosmetic bug in BSDI 4.x wchar.h; thanks to Thomas Wouters */ +# ifdef _HAVE_BSDI +# include +# endif +# include +#endif + +/* Py_UCS4 and Py_UCS2 are typedefs for the respective + unicode representations. */ +#if SIZEOF_INT == 4 +typedef unsigned int Py_UCS4; +#elif SIZEOF_LONG == 4 +typedef unsigned long Py_UCS4; +#else +#error "Could not find a proper typedef for Py_UCS4" +#endif + +#if SIZEOF_SHORT == 2 +typedef unsigned short Py_UCS2; +#else +#error "Could not find a proper typedef for Py_UCS2" +#endif + +typedef unsigned char Py_UCS1; + +/* --- Internal Unicode Operations ---------------------------------------- */ + +/* Since splitting on whitespace is an important use case, and + whitespace in most situations is solely ASCII whitespace, we + optimize for the common case by using a quick look-up table + _Py_ascii_whitespace (see below) with an inlined check. + + */ +#ifndef Py_LIMITED_API +#define Py_UNICODE_ISSPACE(ch) \ + ((ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch)) + +#define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch) +#define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch) +#define Py_UNICODE_ISTITLE(ch) _PyUnicode_IsTitlecase(ch) +#define Py_UNICODE_ISLINEBREAK(ch) _PyUnicode_IsLinebreak(ch) + +#define Py_UNICODE_TOLOWER(ch) _PyUnicode_ToLowercase(ch) +#define Py_UNICODE_TOUPPER(ch) _PyUnicode_ToUppercase(ch) +#define Py_UNICODE_TOTITLE(ch) _PyUnicode_ToTitlecase(ch) + +#define Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch) +#define Py_UNICODE_ISDIGIT(ch) _PyUnicode_IsDigit(ch) +#define Py_UNICODE_ISNUMERIC(ch) _PyUnicode_IsNumeric(ch) +#define Py_UNICODE_ISPRINTABLE(ch) _PyUnicode_IsPrintable(ch) + +#define Py_UNICODE_TODECIMAL(ch) _PyUnicode_ToDecimalDigit(ch) +#define Py_UNICODE_TODIGIT(ch) _PyUnicode_ToDigit(ch) +#define Py_UNICODE_TONUMERIC(ch) _PyUnicode_ToNumeric(ch) + +#define Py_UNICODE_ISALPHA(ch) _PyUnicode_IsAlpha(ch) + +#define Py_UNICODE_ISALNUM(ch) \ + (Py_UNICODE_ISALPHA(ch) || \ + Py_UNICODE_ISDECIMAL(ch) || \ + Py_UNICODE_ISDIGIT(ch) || \ + Py_UNICODE_ISNUMERIC(ch)) + +#define Py_UNICODE_COPY(target, source, length) \ + Py_MEMCPY((target), (source), (length)*sizeof(Py_UNICODE)) + +#define Py_UNICODE_FILL(target, value, length) \ + do {Py_ssize_t i_; Py_UNICODE *t_ = (target); Py_UNICODE v_ = (value);\ + for (i_ = 0; i_ < (length); i_++) t_[i_] = v_;\ + } while (0) + +/* macros to work with surrogates */ +#define Py_UNICODE_IS_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDFFF) +#define Py_UNICODE_IS_HIGH_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDBFF) +#define Py_UNICODE_IS_LOW_SURROGATE(ch) (0xDC00 <= (ch) && (ch) <= 0xDFFF) +/* Join two surrogate characters and return a single Py_UCS4 value. */ +#define Py_UNICODE_JOIN_SURROGATES(high, low) \ + (((((Py_UCS4)(high) & 0x03FF) << 10) | \ + ((Py_UCS4)(low) & 0x03FF)) + 0x10000) +/* high surrogate = top 10 bits added to D800 */ +#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10)) +/* low surrogate = bottom 10 bits added to DC00 */ +#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF)) + +/* Check if substring matches at given offset. The offset must be + valid, and the substring must not be empty. */ + +#define Py_UNICODE_MATCH(string, offset, substring) \ + ((*((string)->wstr + (offset)) == *((substring)->wstr)) && \ + ((*((string)->wstr + (offset) + (substring)->wstr_length-1) == *((substring)->wstr + (substring)->wstr_length-1))) && \ + !memcmp((string)->wstr + (offset), (substring)->wstr, (substring)->wstr_length*sizeof(Py_UNICODE))) + +#endif /* Py_LIMITED_API */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- Unicode Type ------------------------------------------------------- */ + +#ifndef Py_LIMITED_API + +/* ASCII-only strings created through PyUnicode_New use the PyASCIIObject + structure. state.ascii and state.compact are set, and the data + immediately follow the structure. utf8_length and wstr_length can be found + in the length field; the utf8 pointer is equal to the data pointer. */ +typedef struct { + /* There are 4 forms of Unicode strings: + + - compact ascii: + + * structure = PyASCIIObject + * test: PyUnicode_IS_COMPACT_ASCII(op) + * kind = PyUnicode_1BYTE_KIND + * compact = 1 + * ascii = 1 + * ready = 1 + * (length is the length of the utf8 and wstr strings) + * (data starts just after the structure) + * (since ASCII is decoded from UTF-8, the utf8 string are the data) + + - compact: + + * structure = PyCompactUnicodeObject + * test: PyUnicode_IS_COMPACT(op) && !PyUnicode_IS_ASCII(op) + * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or + PyUnicode_4BYTE_KIND + * compact = 1 + * ready = 1 + * ascii = 0 + * utf8 is not shared with data + * utf8_length = 0 if utf8 is NULL + * wstr is shared with data and wstr_length=length + if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 + or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_t)=4 + * wstr_length = 0 if wstr is NULL + * (data starts just after the structure) + + - legacy string, not ready: + + * structure = PyUnicodeObject + * test: kind == PyUnicode_WCHAR_KIND + * length = 0 (use wstr_length) + * hash = -1 + * kind = PyUnicode_WCHAR_KIND + * compact = 0 + * ascii = 0 + * ready = 0 + * interned = SSTATE_NOT_INTERNED + * wstr is not NULL + * data.any is NULL + * utf8 is NULL + * utf8_length = 0 + + - legacy string, ready: + + * structure = PyUnicodeObject structure + * test: !PyUnicode_IS_COMPACT(op) && kind != PyUnicode_WCHAR_KIND + * kind = PyUnicode_1BYTE_KIND, PyUnicode_2BYTE_KIND or + PyUnicode_4BYTE_KIND + * compact = 0 + * ready = 1 + * data.any is not NULL + * utf8 is shared and utf8_length = length with data.any if ascii = 1 + * utf8_length = 0 if utf8 is NULL + * wstr is shared with data.any and wstr_length = length + if kind=PyUnicode_2BYTE_KIND and sizeof(wchar_t)=2 + or if kind=PyUnicode_4BYTE_KIND and sizeof(wchar_4)=4 + * wstr_length = 0 if wstr is NULL + + Compact strings use only one memory block (structure + characters), + whereas legacy strings use one block for the structure and one block + for characters. + + Legacy strings are created by PyUnicode_FromUnicode() and + PyUnicode_FromStringAndSize(NULL, size) functions. They become ready + when PyUnicode_READY() is called. + + See also _PyUnicode_CheckConsistency(). + */ + PyObject_HEAD + Py_ssize_t length; /* Number of code points in the string */ + Py_hash_t hash; /* Hash value; -1 if not set */ + struct { + /* + SSTATE_NOT_INTERNED (0) + SSTATE_INTERNED_MORTAL (1) + SSTATE_INTERNED_IMMORTAL (2) + + If interned != SSTATE_NOT_INTERNED, the two references from the + dictionary to this object are *not* counted in ob_refcnt. + */ + unsigned int interned:2; + /* Character size: + + - PyUnicode_WCHAR_KIND (0): + + * character type = wchar_t (16 or 32 bits, depending on the + platform) + + - PyUnicode_1BYTE_KIND (1): + + * character type = Py_UCS1 (8 bits, unsigned) + * all characters are in the range U+0000-U+00FF (latin1) + * if ascii is set, all characters are in the range U+0000-U+007F + (ASCII), otherwise at least one character is in the range + U+0080-U+00FF + + - PyUnicode_2BYTE_KIND (2): + + * character type = Py_UCS2 (16 bits, unsigned) + * all characters are in the range U+0000-U+FFFF (BMP) + * at least one character is in the range U+0100-U+FFFF + + - PyUnicode_4BYTE_KIND (4): + + * character type = Py_UCS4 (32 bits, unsigned) + * all characters are in the range U+0000-U+10FFFF + * at least one character is in the range U+10000-U+10FFFF + */ + unsigned int kind:3; + /* Compact is with respect to the allocation scheme. Compact unicode + objects only require one memory block while non-compact objects use + one block for the PyUnicodeObject struct and another for its data + buffer. */ + unsigned int compact:1; + /* The string only contains characters in the range U+0000-U+007F (ASCII) + and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is + set, use the PyASCIIObject structure. */ + unsigned int ascii:1; + /* The ready flag indicates whether the object layout is initialized + completely. This means that this is either a compact object, or + the data pointer is filled out. The bit is redundant, and helps + to minimize the test in PyUnicode_IS_READY(). */ + unsigned int ready:1; + /* Padding to ensure that PyUnicode_DATA() is always aligned to + 4 bytes (see issue #19537 on m68k). */ + unsigned int :24; + } state; + wchar_t *wstr; /* wchar_t representation (null-terminated) */ +} PyASCIIObject; + +/* Non-ASCII strings allocated through PyUnicode_New use the + PyCompactUnicodeObject structure. state.compact is set, and the data + immediately follow the structure. */ +typedef struct { + PyASCIIObject _base; + Py_ssize_t utf8_length; /* Number of bytes in utf8, excluding the + * terminating \0. */ + char *utf8; /* UTF-8 representation (null-terminated) */ + Py_ssize_t wstr_length; /* Number of code points in wstr, possible + * surrogates count as two code points. */ +} PyCompactUnicodeObject; + +/* Strings allocated through PyUnicode_FromUnicode(NULL, len) use the + PyUnicodeObject structure. The actual string data is initially in the wstr + block, and copied into the data block using _PyUnicode_Ready. */ +typedef struct { + PyCompactUnicodeObject _base; + union { + void *any; + Py_UCS1 *latin1; + Py_UCS2 *ucs2; + Py_UCS4 *ucs4; + } data; /* Canonical, smallest-form Unicode buffer */ +} PyUnicodeObject; +#endif + +PyAPI_DATA(PyTypeObject) PyUnicode_Type; +PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type; + +#define PyUnicode_Check(op) \ + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS) +#define PyUnicode_CheckExact(op) (Py_TYPE(op) == &PyUnicode_Type) + +/* Fast access macros */ +#ifndef Py_LIMITED_API + +#define PyUnicode_WSTR_LENGTH(op) \ + (PyUnicode_IS_COMPACT_ASCII(op) ? \ + ((PyASCIIObject*)op)->length : \ + ((PyCompactUnicodeObject*)op)->wstr_length) + +/* Returns the deprecated Py_UNICODE representation's size in code units + (this includes surrogate pairs as 2 units). + If the Py_UNICODE representation is not available, it will be computed + on request. Use PyUnicode_GET_LENGTH() for the length in code points. */ + +#define PyUnicode_GET_SIZE(op) \ + (assert(PyUnicode_Check(op)), \ + (((PyASCIIObject *)(op))->wstr) ? \ + PyUnicode_WSTR_LENGTH(op) : \ + ((void)PyUnicode_AsUnicode((PyObject *)(op)), \ + assert(((PyASCIIObject *)(op))->wstr), \ + PyUnicode_WSTR_LENGTH(op))) + +#define PyUnicode_GET_DATA_SIZE(op) \ + (PyUnicode_GET_SIZE(op) * Py_UNICODE_SIZE) + +/* Alias for PyUnicode_AsUnicode(). This will create a wchar_t/Py_UNICODE + representation on demand. Using this macro is very inefficient now, + try to port your code to use the new PyUnicode_*BYTE_DATA() macros or + use PyUnicode_WRITE() and PyUnicode_READ(). */ + +#define PyUnicode_AS_UNICODE(op) \ + (assert(PyUnicode_Check(op)), \ + (((PyASCIIObject *)(op))->wstr) ? (((PyASCIIObject *)(op))->wstr) : \ + PyUnicode_AsUnicode((PyObject *)(op))) + +#define PyUnicode_AS_DATA(op) \ + ((const char *)(PyUnicode_AS_UNICODE(op))) + + +/* --- Flexible String Representation Helper Macros (PEP 393) -------------- */ + +/* Values for PyASCIIObject.state: */ + +/* Interning state. */ +#define SSTATE_NOT_INTERNED 0 +#define SSTATE_INTERNED_MORTAL 1 +#define SSTATE_INTERNED_IMMORTAL 2 + +/* Return true if the string contains only ASCII characters, or 0 if not. The + string may be compact (PyUnicode_IS_COMPACT_ASCII) or not, but must be + ready. */ +#define PyUnicode_IS_ASCII(op) \ + (assert(PyUnicode_Check(op)), \ + assert(PyUnicode_IS_READY(op)), \ + ((PyASCIIObject*)op)->state.ascii) + +/* Return true if the string is compact or 0 if not. + No type checks or Ready calls are performed. */ +#define PyUnicode_IS_COMPACT(op) \ + (((PyASCIIObject*)(op))->state.compact) + +/* Return true if the string is a compact ASCII string (use PyASCIIObject + structure), or 0 if not. No type checks or Ready calls are performed. */ +#define PyUnicode_IS_COMPACT_ASCII(op) \ + (((PyASCIIObject*)op)->state.ascii && PyUnicode_IS_COMPACT(op)) + +enum PyUnicode_Kind { +/* String contains only wstr byte characters. This is only possible + when the string was created with a legacy API and _PyUnicode_Ready() + has not been called yet. */ + PyUnicode_WCHAR_KIND = 0, +/* Return values of the PyUnicode_KIND() macro: */ + PyUnicode_1BYTE_KIND = 1, + PyUnicode_2BYTE_KIND = 2, + PyUnicode_4BYTE_KIND = 4 +}; + +/* Return pointers to the canonical representation cast to unsigned char, + Py_UCS2, or Py_UCS4 for direct character access. + No checks are performed, use PyUnicode_KIND() before to ensure + these will work correctly. */ + +#define PyUnicode_1BYTE_DATA(op) ((Py_UCS1*)PyUnicode_DATA(op)) +#define PyUnicode_2BYTE_DATA(op) ((Py_UCS2*)PyUnicode_DATA(op)) +#define PyUnicode_4BYTE_DATA(op) ((Py_UCS4*)PyUnicode_DATA(op)) + +/* Return one of the PyUnicode_*_KIND values defined above. */ +#define PyUnicode_KIND(op) \ + (assert(PyUnicode_Check(op)), \ + assert(PyUnicode_IS_READY(op)), \ + ((PyASCIIObject *)(op))->state.kind) + +/* Return a void pointer to the raw unicode buffer. */ +#define _PyUnicode_COMPACT_DATA(op) \ + (PyUnicode_IS_ASCII(op) ? \ + ((void*)((PyASCIIObject*)(op) + 1)) : \ + ((void*)((PyCompactUnicodeObject*)(op) + 1))) + +#define _PyUnicode_NONCOMPACT_DATA(op) \ + (assert(((PyUnicodeObject*)(op))->data.any), \ + ((((PyUnicodeObject *)(op))->data.any))) + +#define PyUnicode_DATA(op) \ + (assert(PyUnicode_Check(op)), \ + PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \ + _PyUnicode_NONCOMPACT_DATA(op)) + +/* In the access macros below, "kind" may be evaluated more than once. + All other macro parameters are evaluated exactly once, so it is safe + to put side effects into them (such as increasing the index). */ + +/* Write into the canonical representation, this macro does not do any sanity + checks and is intended for usage in loops. The caller should cache the + kind and data pointers obtained from other macro calls. + index is the index in the string (starts at 0) and value is the new + code point value which should be written to that location. */ +#define PyUnicode_WRITE(kind, data, index, value) \ + do { \ + switch ((kind)) { \ + case PyUnicode_1BYTE_KIND: { \ + ((Py_UCS1 *)(data))[(index)] = (Py_UCS1)(value); \ + break; \ + } \ + case PyUnicode_2BYTE_KIND: { \ + ((Py_UCS2 *)(data))[(index)] = (Py_UCS2)(value); \ + break; \ + } \ + default: { \ + assert((kind) == PyUnicode_4BYTE_KIND); \ + ((Py_UCS4 *)(data))[(index)] = (Py_UCS4)(value); \ + } \ + } \ + } while (0) + +/* Read a code point from the string's canonical representation. No checks + or ready calls are performed. */ +#define PyUnicode_READ(kind, data, index) \ + ((Py_UCS4) \ + ((kind) == PyUnicode_1BYTE_KIND ? \ + ((const Py_UCS1 *)(data))[(index)] : \ + ((kind) == PyUnicode_2BYTE_KIND ? \ + ((const Py_UCS2 *)(data))[(index)] : \ + ((const Py_UCS4 *)(data))[(index)] \ + ) \ + )) + +/* PyUnicode_READ_CHAR() is less efficient than PyUnicode_READ() because it + calls PyUnicode_KIND() and might call it twice. For single reads, use + PyUnicode_READ_CHAR, for multiple consecutive reads callers should + cache kind and use PyUnicode_READ instead. */ +#define PyUnicode_READ_CHAR(unicode, index) \ + (assert(PyUnicode_Check(unicode)), \ + assert(PyUnicode_IS_READY(unicode)), \ + (Py_UCS4) \ + (PyUnicode_KIND((unicode)) == PyUnicode_1BYTE_KIND ? \ + ((const Py_UCS1 *)(PyUnicode_DATA((unicode))))[(index)] : \ + (PyUnicode_KIND((unicode)) == PyUnicode_2BYTE_KIND ? \ + ((const Py_UCS2 *)(PyUnicode_DATA((unicode))))[(index)] : \ + ((const Py_UCS4 *)(PyUnicode_DATA((unicode))))[(index)] \ + ) \ + )) + +/* Returns the length of the unicode string. The caller has to make sure that + the string has it's canonical representation set before calling + this macro. Call PyUnicode_(FAST_)Ready to ensure that. */ +#define PyUnicode_GET_LENGTH(op) \ + (assert(PyUnicode_Check(op)), \ + assert(PyUnicode_IS_READY(op)), \ + ((PyASCIIObject *)(op))->length) + + +/* Fast check to determine whether an object is ready. Equivalent to + PyUnicode_IS_COMPACT(op) || ((PyUnicodeObject*)(op))->data.any) */ + +#define PyUnicode_IS_READY(op) (((PyASCIIObject*)op)->state.ready) + +/* PyUnicode_READY() does less work than _PyUnicode_Ready() in the best + case. If the canonical representation is not yet set, it will still call + _PyUnicode_Ready(). + Returns 0 on success and -1 on errors. */ +#define PyUnicode_READY(op) \ + (assert(PyUnicode_Check(op)), \ + (PyUnicode_IS_READY(op) ? \ + 0 : _PyUnicode_Ready((PyObject *)(op)))) + +/* Return a maximum character value which is suitable for creating another + string based on op. This is always an approximation but more efficient + than iterating over the string. */ +#define PyUnicode_MAX_CHAR_VALUE(op) \ + (assert(PyUnicode_IS_READY(op)), \ + (PyUnicode_IS_ASCII(op) ? \ + (0x7f) : \ + (PyUnicode_KIND(op) == PyUnicode_1BYTE_KIND ? \ + (0xffU) : \ + (PyUnicode_KIND(op) == PyUnicode_2BYTE_KIND ? \ + (0xffffU) : \ + (0x10ffffU))))) + +#endif + +/* --- Constants ---------------------------------------------------------- */ + +/* This Unicode character will be used as replacement character during + decoding if the errors argument is set to "replace". Note: the + Unicode character U+FFFD is the official REPLACEMENT CHARACTER in + Unicode 3.0. */ + +#define Py_UNICODE_REPLACEMENT_CHARACTER ((Py_UCS4) 0xFFFD) + +/* === Public API ========================================================= */ + +/* --- Plain Py_UNICODE --------------------------------------------------- */ + +/* With PEP 393, this is the recommended way to allocate a new unicode object. + This function will allocate the object and its buffer in a single memory + block. Objects created using this function are not resizable. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_New( + Py_ssize_t size, /* Number of code points in the new string */ + Py_UCS4 maxchar /* maximum code point value in the string */ + ); +#endif + +/* Initializes the canonical string representation from the deprecated + wstr/Py_UNICODE representation. This function is used to convert Unicode + objects which were created using the old API to the new flexible format + introduced with PEP 393. + + Don't call this function directly, use the public PyUnicode_READY() macro + instead. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyUnicode_Ready( + PyObject *unicode /* Unicode object */ + ); +#endif + +/* Get a copy of a Unicode string. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyUnicode_Copy( + PyObject *unicode + ); +#endif + +/* Copy character from one unicode object into another, this function performs + character conversion when necessary and falls back to memcpy() if possible. + + Fail if to is too small (smaller than *how_many* or smaller than + len(from)-from_start), or if kind(from[from_start:from_start+how_many]) > + kind(to), or if *to* has more than 1 reference. + + Return the number of written character, or return -1 and raise an exception + on error. + + Pseudo-code: + + how_many = min(how_many, len(from) - from_start) + to[to_start:to_start+how_many] = from[from_start:from_start+how_many] + return how_many + + Note: The function doesn't write a terminating null character. + */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) PyUnicode_CopyCharacters( + PyObject *to, + Py_ssize_t to_start, + PyObject *from, + Py_ssize_t from_start, + Py_ssize_t how_many + ); + +/* Unsafe version of PyUnicode_CopyCharacters(): don't check arguments and so + may crash if parameters are invalid (e.g. if the output string + is too short). */ +PyAPI_FUNC(void) _PyUnicode_FastCopyCharacters( + PyObject *to, + Py_ssize_t to_start, + PyObject *from, + Py_ssize_t from_start, + Py_ssize_t how_many + ); +#endif + +#ifndef Py_LIMITED_API +/* Fill a string with a character: write fill_char into + unicode[start:start+length]. + + Fail if fill_char is bigger than the string maximum character, or if the + string has more than 1 reference. + + Return the number of written character, or return -1 and raise an exception + on error. */ +PyAPI_FUNC(Py_ssize_t) PyUnicode_Fill( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t length, + Py_UCS4 fill_char + ); + +/* Unsafe version of PyUnicode_Fill(): don't check arguments and so may crash + if parameters are invalid (e.g. if length is longer than the string). */ +PyAPI_FUNC(void) _PyUnicode_FastFill( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t length, + Py_UCS4 fill_char + ); +#endif + +/* Create a Unicode Object from the Py_UNICODE buffer u of the given + size. + + u may be NULL which causes the contents to be undefined. It is the + user's responsibility to fill in the needed data afterwards. Note + that modifying the Unicode object contents after construction is + only allowed if u was set to NULL. + + The buffer is copied into the new object. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode( + const Py_UNICODE *u, /* Unicode buffer */ + Py_ssize_t size /* size of buffer */ + ); +#endif + +/* Similar to PyUnicode_FromUnicode(), but u points to UTF-8 encoded bytes */ +PyAPI_FUNC(PyObject*) PyUnicode_FromStringAndSize( + const char *u, /* UTF-8 encoded string */ + Py_ssize_t size /* size of buffer */ + ); + +/* Similar to PyUnicode_FromUnicode(), but u points to null-terminated + UTF-8 encoded bytes. The size is determined with strlen(). */ +PyAPI_FUNC(PyObject*) PyUnicode_FromString( + const char *u /* UTF-8 encoded string */ + ); + +#ifndef Py_LIMITED_API +/* Create a new string from a buffer of Py_UCS1, Py_UCS2 or Py_UCS4 characters. + Scan the string to find the maximum character. */ +PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData( + int kind, + const void *buffer, + Py_ssize_t size); + +/* Create a new string from a buffer of ASCII characters. + WARNING: Don't check if the string contains any non-ASCII character. */ +PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII( + const char *buffer, + Py_ssize_t size); +#endif + +PyAPI_FUNC(PyObject*) PyUnicode_Substring( + PyObject *str, + Py_ssize_t start, + Py_ssize_t end); + +#ifndef Py_LIMITED_API +/* Compute the maximum character of the substring unicode[start:end]. + Return 127 for an empty string. */ +PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t end); +#endif + +/* Copy the string into a UCS4 buffer including the null character if copy_null + is set. Return NULL and raise an exception on error. Raise a SystemError if + the buffer is smaller than the string. Return buffer on success. + + buflen is the length of the buffer in (Py_UCS4) characters. */ +PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4( + PyObject *unicode, + Py_UCS4* buffer, + Py_ssize_t buflen, + int copy_null); + +/* Copy the string into a UCS4 buffer. A new buffer is allocated using + * PyMem_Malloc; if this fails, NULL is returned with a memory error + exception set. */ +PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4Copy(PyObject *unicode); + +/* Return a read-only pointer to the Unicode object's internal + Py_UNICODE buffer. + If the wchar_t/Py_UNICODE representation is not yet available, this + function will calculate it. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode( + PyObject *unicode /* Unicode object */ + ); +#endif + +/* Return a read-only pointer to the Unicode object's internal + Py_UNICODE buffer and save the length at size. + If the wchar_t/Py_UNICODE representation is not yet available, this + function will calculate it. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicodeAndSize( + PyObject *unicode, /* Unicode object */ + Py_ssize_t *size /* location where to save the length */ + ); +#endif + +/* Get the length of the Unicode object. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_GetLength( + PyObject *unicode +); + +/* Get the number of Py_UNICODE units in the + string representation. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_GetSize( + PyObject *unicode /* Unicode object */ + ); + +/* Read a character from the string. */ + +PyAPI_FUNC(Py_UCS4) PyUnicode_ReadChar( + PyObject *unicode, + Py_ssize_t index + ); + +/* Write a character to the string. The string must have been created through + PyUnicode_New, must not be shared, and must not have been hashed yet. + + Return 0 on success, -1 on error. */ + +PyAPI_FUNC(int) PyUnicode_WriteChar( + PyObject *unicode, + Py_ssize_t index, + Py_UCS4 character + ); + +#ifndef Py_LIMITED_API +/* Get the maximum ordinal for a Unicode character. */ +PyAPI_FUNC(Py_UNICODE) PyUnicode_GetMax(void); +#endif + +/* Resize a Unicode object. The length is the number of characters, except + if the kind of the string is PyUnicode_WCHAR_KIND: in this case, the length + is the number of Py_UNICODE characters. + + *unicode is modified to point to the new (resized) object and 0 + returned on success. + + Try to resize the string in place (which is usually faster than allocating + a new string and copy characters), or create a new string. + + Error handling is implemented as follows: an exception is set, -1 + is returned and *unicode left untouched. + + WARNING: The function doesn't check string content, the result may not be a + string in canonical representation. */ + +PyAPI_FUNC(int) PyUnicode_Resize( + PyObject **unicode, /* Pointer to the Unicode object */ + Py_ssize_t length /* New length */ + ); + +/* Decode obj to a Unicode object. + + bytes, bytearray and other bytes-like objects are decoded according to the + given encoding and error handler. The encoding and error handler can be + NULL to have the interface use UTF-8 and "strict". + + All other objects (including Unicode objects) raise an exception. + + The API returns NULL in case of an error. The caller is responsible + for decref'ing the returned objects. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromEncodedObject( + PyObject *obj, /* Object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Copy an instance of a Unicode subtype to a new true Unicode object if + necessary. If obj is already a true Unicode object (not a subtype), return + the reference with *incremented* refcount. + + The API returns NULL in case of an error. The caller is responsible + for decref'ing the returned objects. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromObject( + PyObject *obj /* Object */ + ); + +PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV( + const char *format, /* ASCII-encoded string */ + va_list vargs + ); +PyAPI_FUNC(PyObject *) PyUnicode_FromFormat( + const char *format, /* ASCII-encoded string */ + ... + ); + +#ifndef Py_LIMITED_API +typedef struct { + PyObject *buffer; + void *data; + enum PyUnicode_Kind kind; + Py_UCS4 maxchar; + Py_ssize_t size; + Py_ssize_t pos; + + /* minimum number of allocated characters (default: 0) */ + Py_ssize_t min_length; + + /* minimum character (default: 127, ASCII) */ + Py_UCS4 min_char; + + /* If non-zero, overallocate the buffer by 25% (default: 0). */ + unsigned char overallocate; + + /* If readonly is 1, buffer is a shared string (cannot be modified) + and size is set to 0. */ + unsigned char readonly; +} _PyUnicodeWriter ; + +/* Initialize a Unicode writer. + * + * By default, the minimum buffer size is 0 character and overallocation is + * disabled. Set min_length, min_char and overallocate attributes to control + * the allocation of the buffer. */ +PyAPI_FUNC(void) +_PyUnicodeWriter_Init(_PyUnicodeWriter *writer); + +/* Prepare the buffer to write 'length' characters + with the specified maximum character. + + Return 0 on success, raise an exception and return -1 on error. */ +#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \ + (((MAXCHAR) <= (WRITER)->maxchar \ + && (LENGTH) <= (WRITER)->size - (WRITER)->pos) \ + ? 0 \ + : (((LENGTH) == 0) \ + ? 0 \ + : _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR)))) + +/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro + instead. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, + Py_ssize_t length, Py_UCS4 maxchar); + +/* Append a Unicode character. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, + Py_UCS4 ch + ); + +/* Append a Unicode string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, + PyObject *str /* Unicode string */ + ); + +/* Append a substring of a Unicode string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, + PyObject *str, /* Unicode string */ + Py_ssize_t start, + Py_ssize_t end + ); + +/* Append an ASCII-encoded byte string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, + const char *str, /* ASCII-encoded byte string */ + Py_ssize_t len /* number of bytes, or -1 if unknown */ + ); + +/* Append a latin1-encoded byte string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, + const char *str, /* latin1-encoded byte string */ + Py_ssize_t len /* length in bytes */ + ); + +/* Get the value of the writer as a Unicode string. Clear the + buffer of the writer. Raise an exception and return NULL + on error. */ +PyAPI_FUNC(PyObject *) +_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer); + +/* Deallocate memory of a writer (clear its internal buffer). */ +PyAPI_FUNC(void) +_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); +#endif + +#ifndef Py_LIMITED_API +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); +#endif + +PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **); +PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); +PyAPI_FUNC(PyObject *) PyUnicode_InternFromString( + const char *u /* UTF-8 encoded string */ + ); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_ReleaseInternedUnicodeStrings(void); +#endif + +/* Use only if you know it's a string */ +#define PyUnicode_CHECK_INTERNED(op) \ + (((PyASCIIObject *)(op))->state.interned) + +/* --- wchar_t support for platforms which support it --------------------- */ + +#ifdef HAVE_WCHAR_H + +/* Create a Unicode Object from the wchar_t buffer w of the given + size. + + The buffer is copied into the new object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_FromWideChar( + const wchar_t *w, /* wchar_t buffer */ + Py_ssize_t size /* size of buffer */ + ); + +/* Copies the Unicode Object contents into the wchar_t buffer w. At + most size wchar_t characters are copied. + + Note that the resulting wchar_t string may or may not be + 0-terminated. It is the responsibility of the caller to make sure + that the wchar_t string is 0-terminated in case this is required by + the application. + + Returns the number of wchar_t characters copied (excluding a + possibly trailing 0-termination character) or -1 in case of an + error. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_AsWideChar( + PyObject *unicode, /* Unicode object */ + wchar_t *w, /* wchar_t buffer */ + Py_ssize_t size /* size of buffer */ + ); + +/* Convert the Unicode object to a wide character string. The output string + always ends with a nul character. If size is not NULL, write the number of + wide characters (excluding the null character) into *size. + + Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) + on success. On error, returns NULL, *size is undefined and raises a + MemoryError. */ + +PyAPI_FUNC(wchar_t*) PyUnicode_AsWideCharString( + PyObject *unicode, /* Unicode object */ + Py_ssize_t *size /* number of characters of the result */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(void*) _PyUnicode_AsKind(PyObject *s, unsigned int kind); +#endif + +#endif + +/* --- Unicode ordinals --------------------------------------------------- */ + +/* Create a Unicode Object from the given Unicode code point ordinal. + + The ordinal must be in range(0x110000). A ValueError is + raised in case it is not. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromOrdinal(int ordinal); + +/* --- Free-list management ----------------------------------------------- */ + +/* Clear the free list used by the Unicode implementation. + + This can be used to release memory used for objects on the free + list back to the Python memory allocator. + +*/ + +PyAPI_FUNC(int) PyUnicode_ClearFreeList(void); + +/* === Builtin Codecs ===================================================== + + Many of these APIs take two arguments encoding and errors. These + parameters encoding and errors have the same semantics as the ones + of the builtin str() API. + + Setting encoding to NULL causes the default encoding (UTF-8) to be used. + + Error handling is set by errors which may also be set to NULL + meaning to use the default handling defined for the codec. Default + error handling for all builtin codecs is "strict" (ValueErrors are + raised). + + The codecs all use a similar interface. Only deviation from the + generic ones are documented. + +*/ + +/* --- Manage the default encoding ---------------------------------------- */ + +/* Returns a pointer to the default encoding (UTF-8) of the + Unicode object unicode and the size of the encoded representation + in bytes stored in *size. + + In case of an error, no *size is set. + + This function caches the UTF-8 encoded string in the unicodeobject + and subsequent calls will return the same string. The memory is released + when the unicodeobject is deallocated. + + _PyUnicode_AsStringAndSize is a #define for PyUnicode_AsUTF8AndSize to + support the previous internal function with the same behaviour. + + *** This API is for interpreter INTERNAL USE ONLY and will likely + *** be removed or changed in the future. + + *** If you need to access the Unicode object as UTF-8 bytes string, + *** please use PyUnicode_AsUTF8String() instead. +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(char *) PyUnicode_AsUTF8AndSize( + PyObject *unicode, + Py_ssize_t *size); +#define _PyUnicode_AsStringAndSize PyUnicode_AsUTF8AndSize +#endif + +/* Returns a pointer to the default encoding (UTF-8) of the + Unicode object unicode. + + Like PyUnicode_AsUTF8AndSize(), this also caches the UTF-8 representation + in the unicodeobject. + + _PyUnicode_AsString is a #define for PyUnicode_AsUTF8 to + support the previous internal function with the same behaviour. + + Use of this API is DEPRECATED since no size information can be + extracted from the returned data. + + *** This API is for interpreter INTERNAL USE ONLY and will likely + *** be removed or changed for Python 3.1. + + *** If you need to access the Unicode object as UTF-8 bytes string, + *** please use PyUnicode_AsUTF8String() instead. + +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(char *) PyUnicode_AsUTF8(PyObject *unicode); +#define _PyUnicode_AsString PyUnicode_AsUTF8 +#endif + +/* Returns "utf-8". */ + +PyAPI_FUNC(const char*) PyUnicode_GetDefaultEncoding(void); + +/* --- Generic Codecs ----------------------------------------------------- */ + +/* Create a Unicode object by decoding the encoded string s of the + given size. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Decode( + const char *s, /* encoded string */ + Py_ssize_t size, /* size of buffer */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Decode a Unicode object unicode and return the result as Python + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedObject( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Decode a Unicode object unicode and return the result as Unicode + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsDecodedUnicode( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Py_UNICODE buffer of the given size and returns a + Python string object. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_Encode( + const Py_UNICODE *s, /* Unicode char buffer */ + Py_ssize_t size, /* number of Py_UNICODE chars to encode */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); +#endif + +/* Encodes a Unicode object and returns the result as Python + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Unicode object and returns the result as Python string + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedString( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Unicode object and returns the result as Unicode + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedUnicode( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Build an encoding map. */ + +PyAPI_FUNC(PyObject*) PyUnicode_BuildEncodingMap( + PyObject* string /* 256 character map */ + ); + +/* --- UTF-7 Codecs ------------------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7( + const char *string, /* UTF-7 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7Stateful( + const char *string, /* UTF-7 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF7( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + int base64SetO, /* Encode RFC2152 Set O characters in base64 */ + int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ + const char *errors /* error handling */ + ); +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF7( + PyObject *unicode, /* Unicode object */ + int base64SetO, /* Encode RFC2152 Set O characters in base64 */ + int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ + const char *errors /* error handling */ + ); +#endif + +/* --- UTF-8 Codecs ------------------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8( + const char *string, /* UTF-8 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8Stateful( + const char *string, /* UTF-8 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsUTF8String( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyUnicode_AsUTF8String( + PyObject *unicode, + const char *errors); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF8( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); +#endif + +/* --- UTF-32 Codecs ------------------------------------------------------ */ + +/* Decodes length bytes from a UTF-32 encoded buffer string and returns + the corresponding Unicode object. + + errors (if non-NULL) defines the error handling. It defaults + to "strict". + + If byteorder is non-NULL, the decoder starts decoding using the + given byte order: + + *byteorder == -1: little endian + *byteorder == 0: native order + *byteorder == 1: big endian + + In native mode, the first four bytes of the stream are checked for a + BOM mark. If found, the BOM mark is analysed, the byte order + adjusted and the BOM skipped. In the other modes, no BOM mark + interpretation is done. After completion, *byteorder is set to the + current byte order at the end of input data. + + If byteorder is NULL, the codec starts in native order mode. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32( + const char *string, /* UTF-32 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF32Stateful( + const char *string, /* UTF-32 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder, /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +/* Returns a Python string using the UTF-32 encoding in native byte + order. The string always starts with a BOM mark. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsUTF32String( + PyObject *unicode /* Unicode object */ + ); + +/* Returns a Python string object holding the UTF-32 encoded value of + the Unicode data. + + If byteorder is not 0, output is written according to the following + byte order: + + byteorder == -1: little endian + byteorder == 0: native byte order (writes a BOM mark) + byteorder == 1: big endian + + If byteorder is 0, the output string will always start with the + Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is + prepended. + +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF32( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors, /* error handling */ + int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + ); +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF32( + PyObject *object, /* Unicode object */ + const char *errors, /* error handling */ + int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + ); +#endif + +/* --- UTF-16 Codecs ------------------------------------------------------ */ + +/* Decodes length bytes from a UTF-16 encoded buffer string and returns + the corresponding Unicode object. + + errors (if non-NULL) defines the error handling. It defaults + to "strict". + + If byteorder is non-NULL, the decoder starts decoding using the + given byte order: + + *byteorder == -1: little endian + *byteorder == 0: native order + *byteorder == 1: big endian + + In native mode, the first two bytes of the stream are checked for a + BOM mark. If found, the BOM mark is analysed, the byte order + adjusted and the BOM skipped. In the other modes, no BOM mark + interpretation is done. After completion, *byteorder is set to the + current byte order at the end of input data. + + If byteorder is NULL, the codec starts in native order mode. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16( + const char *string, /* UTF-16 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16Stateful( + const char *string, /* UTF-16 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder, /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +/* Returns a Python string using the UTF-16 encoding in native byte + order. The string always starts with a BOM mark. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsUTF16String( + PyObject *unicode /* Unicode object */ + ); + +/* Returns a Python string object holding the UTF-16 encoded value of + the Unicode data. + + If byteorder is not 0, output is written according to the following + byte order: + + byteorder == -1: little endian + byteorder == 0: native byte order (writes a BOM mark) + byteorder == 1: big endian + + If byteorder is 0, the output string will always start with the + Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is + prepended. + + Note that Py_UNICODE data is being interpreted as UTF-16 reduced to + UCS-2. This trick makes it possible to add full UTF-16 capabilities + at a later point without compromising the APIs. + +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF16( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors, /* error handling */ + int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + ); +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF16( + PyObject* unicode, /* Unicode object */ + const char *errors, /* error handling */ + int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + ); +#endif + +/* --- Unicode-Escape Codecs ---------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUnicodeEscape( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUnicodeEscape( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length /* Number of Py_UNICODE chars to encode */ + ); +#endif + +/* --- Raw-Unicode-Escape Codecs ------------------------------------------ */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeRawUnicodeEscape( + const char *string, /* Raw-Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsRawUnicodeEscapeString( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeRawUnicodeEscape( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length /* Number of Py_UNICODE chars to encode */ + ); +#endif + +/* --- Unicode Internal Codec --------------------------------------------- + + Only for internal use in _codecsmodule.c */ + +#ifndef Py_LIMITED_API +PyObject *_PyUnicode_DecodeUnicodeInternal( + const char *string, + Py_ssize_t length, + const char *errors + ); +#endif + +/* --- Latin-1 Codecs ----------------------------------------------------- + + Note: Latin-1 corresponds to the first 256 Unicode ordinals. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeLatin1( + const char *string, /* Latin-1 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsLatin1String( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyUnicode_AsLatin1String( + PyObject* unicode, + const char* errors); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeLatin1( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); +#endif + +/* --- ASCII Codecs ------------------------------------------------------- + + Only 7-bit ASCII data is excepted. All other codes generate errors. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeASCII( + const char *string, /* ASCII encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsASCIIString( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyUnicode_AsASCIIString( + PyObject* unicode, + const char* errors); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeASCII( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); +#endif + +/* --- Character Map Codecs ----------------------------------------------- + + This codec uses mappings to encode and decode characters. + + Decoding mappings must map single string characters to single + Unicode characters, integers (which are then interpreted as Unicode + ordinals) or None (meaning "undefined mapping" and causing an + error). + + Encoding mappings must map single Unicode characters to single + string characters, integers (which are then interpreted as Latin-1 + ordinals) or None (meaning "undefined mapping" and causing an + error). + + If a character lookup fails with a LookupError, the character is + copied as-is meaning that its ordinal value will be interpreted as + Unicode or Latin-1 ordinal resp. Because of this mappings only need + to contain those mappings which map characters to different code + points. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeCharmap( + const char *string, /* Encoded string */ + Py_ssize_t length, /* size of string */ + PyObject *mapping, /* character mapping + (char ordinal -> unicode ordinal) */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsCharmapString( + PyObject *unicode, /* Unicode object */ + PyObject *mapping /* character mapping + (unicode ordinal -> char ordinal) */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + PyObject *mapping, /* character mapping + (unicode ordinal -> char ordinal) */ + const char *errors /* error handling */ + ); +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeCharmap( + PyObject *unicode, /* Unicode object */ + PyObject *mapping, /* character mapping + (unicode ordinal -> char ordinal) */ + const char *errors /* error handling */ + ); +#endif + +/* Translate a Py_UNICODE buffer of the given length by applying a + character mapping table to it and return the resulting Unicode + object. + + The mapping table must map Unicode ordinal integers to Unicode + ordinal integers or None (causing deletion of the character). + + Mapping tables may be dictionaries or sequences. Unmapped character + ordinals (ones which cause a LookupError) are left untouched and + are copied as-is. + +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) PyUnicode_TranslateCharmap( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + PyObject *table, /* Translate table */ + const char *errors /* error handling */ + ); +#endif + +#ifdef HAVE_MBCS + +/* --- MBCS codecs for Windows -------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCS( + const char *string, /* MBCS encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCSStateful( + const char *string, /* MBCS encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeCodePageStateful( + int code_page, /* code page number */ + const char *string, /* encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsMBCSString( + PyObject *unicode /* Unicode object */ + ); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_EncodeMBCS( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); +#endif + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeCodePage( + int code_page, /* code page number */ + PyObject *unicode, /* Unicode object */ + const char *errors /* error handling */ + ); + +#endif /* HAVE_MBCS */ + +/* --- Decimal Encoder ---------------------------------------------------- */ + +/* Takes a Unicode string holding a decimal value and writes it into + an output buffer using standard ASCII digit codes. + + The output buffer has to provide at least length+1 bytes of storage + area. The output string is 0-terminated. + + The encoder converts whitespace to ' ', decimal characters to their + corresponding ASCII digit and all other Latin-1 characters except + \0 as-is. Characters outside this range (Unicode ordinals 1-256) + are treated as errors. This includes embedded NULL bytes. + + Error handling is defined by the errors argument: + + NULL or "strict": raise a ValueError + "ignore": ignore the wrong characters (these are not copied to the + output buffer) + "replace": replaces illegal characters with '?' + + Returns 0 on success, -1 on failure. + +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyUnicode_EncodeDecimal( + Py_UNICODE *s, /* Unicode buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + char *output, /* Output buffer; must have size >= length */ + const char *errors /* error handling */ + ); +#endif + +/* Transforms code points that have decimal digit property to the + corresponding ASCII digit code points. + + Returns a new Unicode string on success, NULL on failure. +*/ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) PyUnicode_TransformDecimalToASCII( + Py_UNICODE *s, /* Unicode buffer */ + Py_ssize_t length /* Number of Py_UNICODE chars to transform */ + ); +#endif + +/* Similar to PyUnicode_TransformDecimalToASCII(), but takes a PyObject + as argument instead of a raw buffer and length. This function additionally + transforms spaces to ASCII because this is what the callers in longobject, + floatobject, and complexobject did anyways. */ + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( + PyObject *unicode /* Unicode object */ + ); +#endif + +/* --- Locale encoding --------------------------------------------------- */ + +/* Decode a string from the current locale encoding. The decoder is strict if + *surrogateescape* is equal to zero, otherwise it uses the 'surrogateescape' + error handler (PEP 383) to escape undecodable bytes. If a byte sequence can + be decoded as a surrogate character and *surrogateescape* is not equal to + zero, the byte sequence is escaped using the 'surrogateescape' error handler + instead of being decoded. *str* must end with a null character but cannot + contain embedded null characters. */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocaleAndSize( + const char *str, + Py_ssize_t len, + const char *errors); + +/* Similar to PyUnicode_DecodeLocaleAndSize(), but compute the string + length using strlen(). */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeLocale( + const char *str, + const char *errors); + +/* Encode a Unicode object to the current locale encoding. The encoder is + strict is *surrogateescape* is equal to zero, otherwise the + "surrogateescape" error handler is used. Return a bytes object. The string + cannot contain embedded null characters. */ + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeLocale( + PyObject *unicode, + const char *errors + ); + +/* --- File system encoding ---------------------------------------------- */ + +/* ParseTuple converter: encode str objects to bytes using + PyUnicode_EncodeFSDefault(); bytes objects are output as-is. */ + +PyAPI_FUNC(int) PyUnicode_FSConverter(PyObject*, void*); + +/* ParseTuple converter: decode bytes objects to unicode using + PyUnicode_DecodeFSDefaultAndSize(); str objects are output as-is. */ + +PyAPI_FUNC(int) PyUnicode_FSDecoder(PyObject*, void*); + +/* Decode a null-terminated string using Py_FileSystemDefaultEncoding + and the "surrogateescape" error handler. + + If Py_FileSystemDefaultEncoding is not set, fall back to the locale + encoding. + + Use PyUnicode_DecodeFSDefaultAndSize() if the string length is known. +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefault( + const char *s /* encoded string */ + ); + +/* Decode a string using Py_FileSystemDefaultEncoding + and the "surrogateescape" error handler. + + If Py_FileSystemDefaultEncoding is not set, fall back to the locale + encoding. +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeFSDefaultAndSize( + const char *s, /* encoded string */ + Py_ssize_t size /* size */ + ); + +/* Encode a Unicode object to Py_FileSystemDefaultEncoding with the + "surrogateescape" error handler, and return bytes. + + If Py_FileSystemDefaultEncoding is not set, fall back to the locale + encoding. +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeFSDefault( + PyObject *unicode + ); + +/* --- Methods & Slots ---------------------------------------------------- + + These are capable of handling Unicode objects and strings on input + (we refer to them as strings in the descriptions) and return + Unicode objects or integers as appropriate. */ + +/* Concat two strings giving a new Unicode string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Concat( + PyObject *left, /* Left string */ + PyObject *right /* Right string */ + ); + +/* Concat two strings and put the result in *pleft + (sets *pleft to NULL on error) */ + +PyAPI_FUNC(void) PyUnicode_Append( + PyObject **pleft, /* Pointer to left string */ + PyObject *right /* Right string */ + ); + +/* Concat two strings, put the result in *pleft and drop the right object + (sets *pleft to NULL on error) */ + +PyAPI_FUNC(void) PyUnicode_AppendAndDel( + PyObject **pleft, /* Pointer to left string */ + PyObject *right /* Right string */ + ); + +/* Split a string giving a list of Unicode strings. + + If sep is NULL, splitting will be done at all whitespace + substrings. Otherwise, splits occur at the given separator. + + At most maxsplit splits will be done. If negative, no limit is set. + + Separators are not included in the resulting list. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_Split( + PyObject *s, /* String to split */ + PyObject *sep, /* String separator */ + Py_ssize_t maxsplit /* Maxsplit count */ + ); + +/* Dito, but split at line breaks. + + CRLF is considered to be one line break. Line breaks are not + included in the resulting list. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Splitlines( + PyObject *s, /* String to split */ + int keepends /* If true, line end markers are included */ + ); + +/* Partition a string using a given separator. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Partition( + PyObject *s, /* String to partition */ + PyObject *sep /* String separator */ + ); + +/* Partition a string using a given separator, searching from the end of the + string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_RPartition( + PyObject *s, /* String to partition */ + PyObject *sep /* String separator */ + ); + +/* Split a string giving a list of Unicode strings. + + If sep is NULL, splitting will be done at all whitespace + substrings. Otherwise, splits occur at the given separator. + + At most maxsplit splits will be done. But unlike PyUnicode_Split + PyUnicode_RSplit splits from the end of the string. If negative, + no limit is set. + + Separators are not included in the resulting list. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_RSplit( + PyObject *s, /* String to split */ + PyObject *sep, /* String separator */ + Py_ssize_t maxsplit /* Maxsplit count */ + ); + +/* Translate a string by applying a character mapping table to it and + return the resulting Unicode object. + + The mapping table must map Unicode ordinal integers to Unicode + ordinal integers or None (causing deletion of the character). + + Mapping tables may be dictionaries or sequences. Unmapped character + ordinals (ones which cause a LookupError) are left untouched and + are copied as-is. + +*/ + +PyAPI_FUNC(PyObject *) PyUnicode_Translate( + PyObject *str, /* String */ + PyObject *table, /* Translate table */ + const char *errors /* error handling */ + ); + +/* Join a sequence of strings using the given separator and return + the resulting Unicode string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Join( + PyObject *separator, /* Separator string */ + PyObject *seq /* Sequence object */ + ); + +/* Return 1 if substr matches str[start:end] at the given tail end, 0 + otherwise. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Tailmatch( + PyObject *str, /* String */ + PyObject *substr, /* Prefix or Suffix string */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end, /* Stop index */ + int direction /* Tail end: -1 prefix, +1 suffix */ + ); + +/* Return the first position of substr in str[start:end] using the + given search direction or -1 if not found. -2 is returned in case + an error occurred and an exception is set. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Find( + PyObject *str, /* String */ + PyObject *substr, /* Substring to find */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end, /* Stop index */ + int direction /* Find direction: +1 forward, -1 backward */ + ); + +/* Like PyUnicode_Find, but search for single character only. */ +PyAPI_FUNC(Py_ssize_t) PyUnicode_FindChar( + PyObject *str, + Py_UCS4 ch, + Py_ssize_t start, + Py_ssize_t end, + int direction + ); + +/* Count the number of occurrences of substr in str[start:end]. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Count( + PyObject *str, /* String */ + PyObject *substr, /* Substring to count */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end /* Stop index */ + ); + +/* Replace at most maxcount occurrences of substr in str with replstr + and return the resulting Unicode object. */ + +PyAPI_FUNC(PyObject *) PyUnicode_Replace( + PyObject *str, /* String */ + PyObject *substr, /* Substring to find */ + PyObject *replstr, /* Substring to replace */ + Py_ssize_t maxcount /* Max. number of replacements to apply; + -1 = all */ + ); + +/* Compare two strings and return -1, 0, 1 for less than, equal, + greater than resp. + Raise an exception and return -1 on error. */ + +PyAPI_FUNC(int) PyUnicode_Compare( + PyObject *left, /* Left string */ + PyObject *right /* Right string */ + ); + +#ifndef Py_LIMITED_API +/* Compare a string with an identifier and return -1, 0, 1 for less than, + equal, and greater than, respectively. + Raise an exception and return -1 on error. */ + +PyAPI_FUNC(int) _PyUnicode_CompareWithId( + PyObject *left, /* Left string */ + _Py_Identifier *right /* Right identifier */ + ); + +/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, + 0 otherwise. Return 0 if any argument contains non-ASCII characters. + Any error occurs inside will be cleared before return. */ + +PyAPI_FUNC(int) _PyUnicode_EqualToASCIIId( + PyObject *left, /* Left string */ + _Py_Identifier *right /* Right identifier */ + ); +#endif + +/* Compare a Unicode object with C string and return -1, 0, 1 for less than, + equal, and greater than, respectively. It is best to pass only + ASCII-encoded strings, but the function interprets the input string as + ISO-8859-1 if it contains non-ASCII characters. + This function does not raise exceptions. */ + +PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString( + PyObject *left, + const char *right /* ASCII-encoded string */ + ); + +#ifndef Py_LIMITED_API +/* Test whether a unicode is equal to ASCII string. Return 1 if true, + 0 otherwise. Return 0 if any argument contains non-ASCII characters. + Any error occurs inside will be cleared before return. */ + +PyAPI_FUNC(int) _PyUnicode_EqualToASCIIString( + PyObject *left, + const char *right /* ASCII-encoded string */ + ); +#endif + +/* Rich compare two strings and return one of the following: + + - NULL in case an exception was raised + - Py_True or Py_False for successful comparisons + - Py_NotImplemented in case the type combination is unknown + + Possible values for op: + + Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE + +*/ + +PyAPI_FUNC(PyObject *) PyUnicode_RichCompare( + PyObject *left, /* Left string */ + PyObject *right, /* Right string */ + int op /* Operation: Py_EQ, Py_NE, Py_GT, etc. */ + ); + +/* Apply an argument tuple or dictionary to a format string and return + the resulting Unicode string. */ + +PyAPI_FUNC(PyObject *) PyUnicode_Format( + PyObject *format, /* Format string */ + PyObject *args /* Argument tuple or dictionary */ + ); + +/* Checks whether element is contained in container and return 1/0 + accordingly. + + element has to coerce to a one element Unicode string. -1 is + returned in case of an error. */ + +PyAPI_FUNC(int) PyUnicode_Contains( + PyObject *container, /* Container string */ + PyObject *element /* Element string */ + ); + +/* Checks whether argument is a valid identifier. */ + +PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s); + +#ifndef Py_LIMITED_API +/* Externally visible for str.strip(unicode) */ +PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( + PyObject *self, + int striptype, + PyObject *sepobj + ); +#endif + +/* Using explicit passed-in values, insert the thousands grouping + into the string pointed to by buffer. For the argument descriptions, + see Objects/stringlib/localeutil.h */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( + PyObject *unicode, + Py_ssize_t index, + Py_ssize_t n_buffer, + void *digits, + Py_ssize_t n_digits, + Py_ssize_t min_width, + const char *grouping, + PyObject *thousands_sep, + Py_UCS4 *maxchar); +#endif +/* === Characters Type APIs =============================================== */ + +/* Helper array used by Py_UNICODE_ISSPACE(). */ + +#ifndef Py_LIMITED_API +PyAPI_DATA(const unsigned char) _Py_ascii_whitespace[]; + +/* These should not be used directly. Use the Py_UNICODE_IS* and + Py_UNICODE_TO* macros instead. + + These APIs are implemented in Objects/unicodectype.c. + +*/ + +PyAPI_FUNC(int) _PyUnicode_IsLowercase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsUppercase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsTitlecase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsXidStart( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsXidContinue( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsWhitespace( + const Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsLinebreak( + const Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UCS4) _PyUnicode_ToLowercase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UCS4) _PyUnicode_ToUppercase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UCS4) _PyUnicode_ToTitlecase( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_ToLowerFull( + Py_UCS4 ch, /* Unicode character */ + Py_UCS4 *res + ); + +PyAPI_FUNC(int) _PyUnicode_ToTitleFull( + Py_UCS4 ch, /* Unicode character */ + Py_UCS4 *res + ); + +PyAPI_FUNC(int) _PyUnicode_ToUpperFull( + Py_UCS4 ch, /* Unicode character */ + Py_UCS4 *res + ); + +PyAPI_FUNC(int) _PyUnicode_ToFoldedFull( + Py_UCS4 ch, /* Unicode character */ + Py_UCS4 *res + ); + +PyAPI_FUNC(int) _PyUnicode_IsCaseIgnorable( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsCased( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_ToDecimalDigit( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_ToDigit( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(double) _PyUnicode_ToNumeric( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsDecimalDigit( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsDigit( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsNumeric( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsPrintable( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsAlpha( + Py_UCS4 ch /* Unicode character */ + ); + +PyAPI_FUNC(size_t) Py_UNICODE_strlen( + const Py_UNICODE *u + ); + +PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcpy( + Py_UNICODE *s1, + const Py_UNICODE *s2); + +PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strcat( + Py_UNICODE *s1, const Py_UNICODE *s2); + +PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strncpy( + Py_UNICODE *s1, + const Py_UNICODE *s2, + size_t n); + +PyAPI_FUNC(int) Py_UNICODE_strcmp( + const Py_UNICODE *s1, + const Py_UNICODE *s2 + ); + +PyAPI_FUNC(int) Py_UNICODE_strncmp( + const Py_UNICODE *s1, + const Py_UNICODE *s2, + size_t n + ); + +PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strchr( + const Py_UNICODE *s, + Py_UNICODE c + ); + +PyAPI_FUNC(Py_UNICODE*) Py_UNICODE_strrchr( + const Py_UNICODE *s, + Py_UNICODE c + ); + +PyAPI_FUNC(PyObject*) _PyUnicode_FormatLong(PyObject *, int, int, int); + +/* Create a copy of a unicode string ending with a nul character. Return NULL + and raise a MemoryError exception on memory allocation failure, otherwise + return a new allocated buffer (use PyMem_Free() to free the buffer). */ + +PyAPI_FUNC(Py_UNICODE*) PyUnicode_AsUnicodeCopy( + PyObject *unicode + ); +#endif /* Py_LIMITED_API */ + +#if defined(Py_DEBUG) && !defined(Py_LIMITED_API) +PyAPI_FUNC(int) _PyUnicode_CheckConsistency( + PyObject *op, + int check_content); +#endif + +/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/ +PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); +/* Clear all static strings. */ +PyAPI_FUNC(void) _PyUnicode_ClearStaticStrings(void); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_UNICODEOBJECT_H */ diff --git a/libs/nxpy/include/warnings.h b/libs/nxpy/include/warnings.h index effb9fad..f7150d1b 100644 --- a/libs/nxpy/include/warnings.h +++ b/libs/nxpy/include/warnings.h @@ -1,54 +1,54 @@ -#ifndef Py_WARNINGS_H -#define Py_WARNINGS_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject*) _PyWarnings_Init(void); -#endif - -PyAPI_FUNC(int) PyErr_WarnEx( - PyObject *category, - const char *message, /* UTF-8 encoded string */ - Py_ssize_t stack_level); -PyAPI_FUNC(int) PyErr_WarnFormat( - PyObject *category, - Py_ssize_t stack_level, - const char *format, /* ASCII-encoded string */ - ...); -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyErr_WarnExplicitObject( - PyObject *category, - PyObject *message, - PyObject *filename, - int lineno, - PyObject *module, - PyObject *registry); -#endif -PyAPI_FUNC(int) PyErr_WarnExplicit( - PyObject *category, - const char *message, /* UTF-8 encoded string */ - const char *filename, /* decoded from the filesystem encoding */ - int lineno, - const char *module, /* UTF-8 encoded string */ - PyObject *registry); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) -PyErr_WarnExplicitFormat(PyObject *category, - const char *filename, int lineno, - const char *module, PyObject *registry, - const char *format, ...); -#endif - -/* DEPRECATED: Use PyErr_WarnEx() instead. */ -#ifndef Py_LIMITED_API -#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) -#endif - -#ifdef __cplusplus -} -#endif -#endif /* !Py_WARNINGS_H */ - +#ifndef Py_WARNINGS_H +#define Py_WARNINGS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyWarnings_Init(void); +#endif + +PyAPI_FUNC(int) PyErr_WarnEx( + PyObject *category, + const char *message, /* UTF-8 encoded string */ + Py_ssize_t stack_level); +PyAPI_FUNC(int) PyErr_WarnFormat( + PyObject *category, + Py_ssize_t stack_level, + const char *format, /* ASCII-encoded string */ + ...); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) PyErr_WarnExplicitObject( + PyObject *category, + PyObject *message, + PyObject *filename, + int lineno, + PyObject *module, + PyObject *registry); +#endif +PyAPI_FUNC(int) PyErr_WarnExplicit( + PyObject *category, + const char *message, /* UTF-8 encoded string */ + const char *filename, /* decoded from the filesystem encoding */ + int lineno, + const char *module, /* UTF-8 encoded string */ + PyObject *registry); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) +PyErr_WarnExplicitFormat(PyObject *category, + const char *filename, int lineno, + const char *module, PyObject *registry, + const char *format, ...); +#endif + +/* DEPRECATED: Use PyErr_WarnEx() instead. */ +#ifndef Py_LIMITED_API +#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_WARNINGS_H */ + diff --git a/libs/nxpy/include/weakrefobject.h b/libs/nxpy/include/weakrefobject.h index 17051568..87acf95c 100644 --- a/libs/nxpy/include/weakrefobject.h +++ b/libs/nxpy/include/weakrefobject.h @@ -1,86 +1,86 @@ -/* Weak references objects for Python. */ - -#ifndef Py_WEAKREFOBJECT_H -#define Py_WEAKREFOBJECT_H -#ifdef __cplusplus -extern "C" { -#endif - - -typedef struct _PyWeakReference PyWeakReference; - -/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, - * and CallableProxyType. - */ -#ifndef Py_LIMITED_API -struct _PyWeakReference { - PyObject_HEAD - - /* The object to which this is a weak reference, or Py_None if none. - * Note that this is a stealth reference: wr_object's refcount is - * not incremented to reflect this pointer. - */ - PyObject *wr_object; - - /* A callable to invoke when wr_object dies, or NULL if none. */ - PyObject *wr_callback; - - /* A cache for wr_object's hash code. As usual for hashes, this is -1 - * if the hash code isn't known yet. - */ - Py_hash_t hash; - - /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- - * terminated list of weak references to it. These are the list pointers. - * If wr_object goes away, wr_object is set to Py_None, and these pointers - * have no meaning then. - */ - PyWeakReference *wr_prev; - PyWeakReference *wr_next; -}; -#endif - -PyAPI_DATA(PyTypeObject) _PyWeakref_RefType; -PyAPI_DATA(PyTypeObject) _PyWeakref_ProxyType; -PyAPI_DATA(PyTypeObject) _PyWeakref_CallableProxyType; - -#define PyWeakref_CheckRef(op) PyObject_TypeCheck(op, &_PyWeakref_RefType) -#define PyWeakref_CheckRefExact(op) \ - (Py_TYPE(op) == &_PyWeakref_RefType) -#define PyWeakref_CheckProxy(op) \ - ((Py_TYPE(op) == &_PyWeakref_ProxyType) || \ - (Py_TYPE(op) == &_PyWeakref_CallableProxyType)) - -#define PyWeakref_Check(op) \ - (PyWeakref_CheckRef(op) || PyWeakref_CheckProxy(op)) - - -PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, - PyObject *callback); -PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, - PyObject *callback); -PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); - -#ifndef Py_LIMITED_API -PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head); - -PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); -#endif - -/* Explanation for the Py_REFCNT() check: when a weakref's target is part - of a long chain of deallocations which triggers the trashcan mechanism, - clearing the weakrefs can be delayed long after the target's refcount - has dropped to zero. In the meantime, code accessing the weakref will - be able to "see" the target object even though it is supposed to be - unreachable. See issue #16602. */ - -#define PyWeakref_GET_OBJECT(ref) \ - (Py_REFCNT(((PyWeakReference *)(ref))->wr_object) > 0 \ - ? ((PyWeakReference *)(ref))->wr_object \ - : Py_None) - - -#ifdef __cplusplus -} -#endif -#endif /* !Py_WEAKREFOBJECT_H */ +/* Weak references objects for Python. */ + +#ifndef Py_WEAKREFOBJECT_H +#define Py_WEAKREFOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct _PyWeakReference PyWeakReference; + +/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, + * and CallableProxyType. + */ +#ifndef Py_LIMITED_API +struct _PyWeakReference { + PyObject_HEAD + + /* The object to which this is a weak reference, or Py_None if none. + * Note that this is a stealth reference: wr_object's refcount is + * not incremented to reflect this pointer. + */ + PyObject *wr_object; + + /* A callable to invoke when wr_object dies, or NULL if none. */ + PyObject *wr_callback; + + /* A cache for wr_object's hash code. As usual for hashes, this is -1 + * if the hash code isn't known yet. + */ + Py_hash_t hash; + + /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- + * terminated list of weak references to it. These are the list pointers. + * If wr_object goes away, wr_object is set to Py_None, and these pointers + * have no meaning then. + */ + PyWeakReference *wr_prev; + PyWeakReference *wr_next; +}; +#endif + +PyAPI_DATA(PyTypeObject) _PyWeakref_RefType; +PyAPI_DATA(PyTypeObject) _PyWeakref_ProxyType; +PyAPI_DATA(PyTypeObject) _PyWeakref_CallableProxyType; + +#define PyWeakref_CheckRef(op) PyObject_TypeCheck(op, &_PyWeakref_RefType) +#define PyWeakref_CheckRefExact(op) \ + (Py_TYPE(op) == &_PyWeakref_RefType) +#define PyWeakref_CheckProxy(op) \ + ((Py_TYPE(op) == &_PyWeakref_ProxyType) || \ + (Py_TYPE(op) == &_PyWeakref_CallableProxyType)) + +#define PyWeakref_Check(op) \ + (PyWeakref_CheckRef(op) || PyWeakref_CheckProxy(op)) + + +PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, + PyObject *callback); +PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, + PyObject *callback); +PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); + +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head); + +PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); +#endif + +/* Explanation for the Py_REFCNT() check: when a weakref's target is part + of a long chain of deallocations which triggers the trashcan mechanism, + clearing the weakrefs can be delayed long after the target's refcount + has dropped to zero. In the meantime, code accessing the weakref will + be able to "see" the target object even though it is supposed to be + unreachable. See issue #16602. */ + +#define PyWeakref_GET_OBJECT(ref) \ + (Py_REFCNT(((PyWeakReference *)(ref))->wr_object) > 0 \ + ? ((PyWeakReference *)(ref))->wr_object \ + : Py_None) + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_WEAKREFOBJECT_H */ diff --git a/romfs/guide/1/1/config.json b/romfs/guide/1/1/config.json index 6422b95d..68aa04bd 100644 --- a/romfs/guide/1/1/config.json +++ b/romfs/guide/1/1/config.json @@ -1,20 +1,20 @@ -{ - "images" : [ - { - "title" : "", - "path" : "banner.bin", - "x" : 0, - "y" : 50, - "w" : 1280, - "h" : 348 - } - ], - "text" : [ - { - "title" : "Introduction", - "path" : "text.txt", - "x" : 50, - "y" : 410 - } - ] +{ + "images" : [ + { + "title" : "", + "path" : "banner.bin", + "x" : 0, + "y" : 50, + "w" : 1280, + "h" : 348 + } + ], + "text" : [ + { + "title" : "Introduction", + "path" : "text.txt", + "x" : 50, + "y" : 410 + } + ] } \ No newline at end of file diff --git a/romfs/guide/1/1/text.txt b/romfs/guide/1/1/text.txt index ccf4ac75..ccbb52e8 100644 --- a/romfs/guide/1/1/text.txt +++ b/romfs/guide/1/1/text.txt @@ -1,7 +1,7 @@ -EdiZon is a all-in-one Homebrew for save file management, save file editing, -memory manipulation and cheat management. This quick start guide will guide you -through all of the features EdiZon has to offer. - -If you have any questions about a topic that isn't covered in this guide (like for example -how to create your own save file editors or cheats) please visit EdiZon's GitHub +EdiZon is a all-in-one Homebrew for save file management, save file editing, +memory manipulation and cheat management. This quick start guide will guide you +through all of the features EdiZon has to offer. + +If you have any questions about a topic that isn't covered in this guide (like for example +how to create your own save file editors or cheats) please visit EdiZon's GitHub Readme and Wiki or join our Discord server. \ No newline at end of file diff --git a/romfs/guide/1/2/auto_updater.txt b/romfs/guide/1/2/auto_updater.txt index fbfe0789..99cfa95e 100644 --- a/romfs/guide/1/2/auto_updater.txt +++ b/romfs/guide/1/2/auto_updater.txt @@ -1,3 +1,3 @@ -EdiZon has a built-in auto-updater. To use it make sure that the console is connected to the internet -and then press the (-) button in the main menu. This will download the latest EdiZon version and all +EdiZon has a built-in auto-updater. To use it make sure that the console is connected to the internet +and then press the (-) button in the main menu. This will download the latest EdiZon version and all latest save editor configs and cheats from the database \ No newline at end of file diff --git a/romfs/guide/1/2/config.json b/romfs/guide/1/2/config.json index 6c1dafd8..0ce2c2ee 100644 --- a/romfs/guide/1/2/config.json +++ b/romfs/guide/1/2/config.json @@ -1,18 +1,18 @@ -{ - "images" : [ - ], - "text" : [ - { - "title" : "Built-in updater", - "path" : "auto_updater.txt", - "x" : 50, - "y" : 100 - }, - { - "title" : "Debug logging", - "path" : "debug_logs.txt", - "x" : 50, - "y" : 300 - } - ] +{ + "images" : [ + ], + "text" : [ + { + "title" : "Built-in updater", + "path" : "auto_updater.txt", + "x" : 50, + "y" : 100 + }, + { + "title" : "Debug logging", + "path" : "debug_logs.txt", + "x" : 50, + "y" : 300 + } + ] } \ No newline at end of file diff --git a/romfs/guide/1/2/debug_logs.txt b/romfs/guide/1/2/debug_logs.txt index 4a80d2a6..aff07b40 100644 --- a/romfs/guide/1/2/debug_logs.txt +++ b/romfs/guide/1/2/debug_logs.txt @@ -1,4 +1,4 @@ -If you experience any issues or if you're a save editor developer it's possible to get some -debug output from EdiZon. The easiest way to do this is by using nxlink which comes with the -devkitpro toolchain. Alternatively you can create a file called EdiZon.log in the /switch/EdiZon +If you experience any issues or if you're a save editor developer it's possible to get some +debug output from EdiZon. The easiest way to do this is by using nxlink which comes with the +devkitpro toolchain. Alternatively you can create a file called EdiZon.log in the /switch/EdiZon folder on your SD card to redirect all console output into that file. \ No newline at end of file diff --git a/romfs/guide/1/3/config.json b/romfs/guide/1/3/config.json index 36a8909e..04432ffe 100644 --- a/romfs/guide/1/3/config.json +++ b/romfs/guide/1/3/config.json @@ -1,20 +1,20 @@ -{ - "images" : [ - { - "title" : "", - "path" : "banner.bin", - "x" : 0, - "y" : 142, - "w" : 1280, - "h" : 256 - } - ], - "text" : [ - { - "title" : "Introduction", - "path" : "text.txt", - "x" : 50, - "y" : 410 - } - ] +{ + "images" : [ + { + "title" : "", + "path" : "banner.bin", + "x" : 0, + "y" : 142, + "w" : 1280, + "h" : 256 + } + ], + "text" : [ + { + "title" : "Introduction", + "path" : "text.txt", + "x" : 50, + "y" : 410 + } + ] } \ No newline at end of file diff --git a/romfs/guide/1/3/text.txt b/romfs/guide/1/3/text.txt index 6f8c3842..d4683925 100644 --- a/romfs/guide/1/3/text.txt +++ b/romfs/guide/1/3/text.txt @@ -1,5 +1,5 @@ -Save file backups are useful if you want to save your current progress in a game so you can -return back to it at a later point or if you're worried about your switch getting stolen or -destroyed in some way. EdiZon is particularly helpful in for the latter since it's possible -to create a batch backup which includes all save files for all games and all users on the +Save file backups are useful if you want to save your current progress in a game so you can +return back to it at a later point or if you're worried about your switch getting stolen or +destroyed in some way. EdiZon is particularly helpful in for the latter since it's possible +to create a batch backup which includes all save files for all games and all users on the system. \ No newline at end of file diff --git a/romfs/guide/1/4/config.json b/romfs/guide/1/4/config.json index b4377872..ef59bdd2 100644 --- a/romfs/guide/1/4/config.json +++ b/romfs/guide/1/4/config.json @@ -1,28 +1,28 @@ -{ - "images" : [ - { - "title" : "Main menu", - "path" : "homemenu.bin", - "x" : 100, - "y" : 325, - "w" : 512, - "h" : 288 - }, - { - "title" : "Save uploading", - "path" : "save_upload.bin", - "x" : 650, - "y" : 325, - "w" : 512, - "h" : 288 - } - ], - "text" : [ - { - "title" : "How to create a save file backup?", - "path" : "text.txt", - "x" : 50, - "y" : 100 - } - ] +{ + "images" : [ + { + "title" : "Main menu", + "path" : "homemenu.bin", + "x" : 100, + "y" : 325, + "w" : 512, + "h" : 288 + }, + { + "title" : "Save uploading", + "path" : "save_upload.bin", + "x" : 650, + "y" : 325, + "w" : 512, + "h" : 288 + } + ], + "text" : [ + { + "title" : "How to create a save file backup?", + "path" : "text.txt", + "x" : 50, + "y" : 100 + } + ] } \ No newline at end of file diff --git a/romfs/guide/1/4/text.txt b/romfs/guide/1/4/text.txt index 0a339415..914e16b8 100644 --- a/romfs/guide/1/4/text.txt +++ b/romfs/guide/1/4/text.txt @@ -1,8 +1,8 @@ -To create a single backup of a game's save data, select the game you want to backup -the save files for in the EdiZon main menu and select the user the save belongs to. In the newly -opened interface, press the (X) button to create a backup. The keyboard will pop up where you can -enter a custom name for the backup folder. By default the current date and time will be used. -Afterwards you'll have the choice to upload the save file to anonfile.com in which case you'll -receive a console-unique key that can be entered on https://edizon.werwolv.net to access all files. -The save file will get stored in /switch/EdiZon/saves/ in both cases. +To create a single backup of a game's save data, select the game you want to backup +the save files for in the EdiZon main menu and select the user the save belongs to. In the newly +opened interface, press the (X) button to create a backup. The keyboard will pop up where you can +enter a custom name for the backup folder. By default the current date and time will be used. +Afterwards you'll have the choice to upload the save file to anonfile.com in which case you'll +receive a console-unique key that can be entered on https://edizon.werwolv.net to access all files. +The save file will get stored in /switch/EdiZon/saves/ in both cases. \ No newline at end of file diff --git a/romfs/guide/1/5/config.json b/romfs/guide/1/5/config.json index 723a06a6..f9ee1ba8 100644 --- a/romfs/guide/1/5/config.json +++ b/romfs/guide/1/5/config.json @@ -1,12 +1,12 @@ -{ - "images" : [ - ], - "text" : [ - { - "title" : "How to create a multi-save backup?", - "path" : "text.txt", - "x" : 50, - "y" : 100 - } - ] +{ + "images" : [ + ], + "text" : [ + { + "title" : "How to create a multi-save backup?", + "path" : "text.txt", + "x" : 50, + "y" : 100 + } + ] } \ No newline at end of file diff --git a/romfs/guide/1/5/text.txt b/romfs/guide/1/5/text.txt index 3efe21ce..38833cd4 100644 --- a/romfs/guide/1/5/text.txt +++ b/romfs/guide/1/5/text.txt @@ -1,11 +1,11 @@ -There are two different types of multi-save backups. - -The first one will create a backup containing all save files of all users for one specific -game. To do this hover over a game's icon in EdiZon's main menu and press the (X) button. -The keyboard will pop up asking you for a name for the backup. After entering the save files -will get copied to /switch/EdiZon/batch. - -The second type is called a batch backup. It will create a backup of all save files on the system. -This can be done by holding down the (ZR) button while pressing the (X) button in the EdiZon -main menu. A warning will pop up and after accepting, the save files will be copied into +There are two different types of multi-save backups. + +The first one will create a backup containing all save files of all users for one specific +game. To do this hover over a game's icon in EdiZon's main menu and press the (X) button. +The keyboard will pop up asking you for a name for the backup. After entering the save files +will get copied to /switch/EdiZon/batch. + +The second type is called a batch backup. It will create a backup of all save files on the system. +This can be done by holding down the (ZR) button while pressing the (X) button in the EdiZon +main menu. A warning will pop up and after accepting, the save files will be copied into /switch/EdiZon/batch. \ No newline at end of file diff --git a/romfs/guide/2/10/config.json b/romfs/guide/2/10/config.json index eccaa43a..c152da25 100644 --- a/romfs/guide/2/10/config.json +++ b/romfs/guide/2/10/config.json @@ -1,12 +1,12 @@ -{ - "images" : [ - ], - "text" : [ - { - "title" : "Value types", - "path" : "text.txt", - "x" : 50, - "y" : 100 - } - ] +{ + "images" : [ + ], + "text" : [ + { + "title" : "Value types", + "path" : "text.txt", + "x" : 50, + "y" : 100 + } + ] } \ No newline at end of file diff --git a/romfs/guide/2/10/text.txt b/romfs/guide/2/10/text.txt index d57b751c..d2d86099 100644 --- a/romfs/guide/2/10/text.txt +++ b/romfs/guide/2/10/text.txt @@ -1,17 +1,17 @@ -The different kinds of widgets are Numbers, On-Off-Switches, Text, Lists, Buttons and Comments. - -Number values can be changed using the left and right dpad buttons. To enter a value using the -keyboard, use the (A) button. To increase the step size multiplier, press the right stick button. - -On-off-Switches can be either enabled or disabled by selecting them and pressing the (A) button. - -Text values allow you to enter your own text using the keyboard. Press the (A) button to open it. - -Lists allow you to choose from a preselected list of values to set the value to. Press the (A) button -to open the list and press the (A) button again to confirm your choice. - -Buttons allow for custom one-time options to be executed. Be aware that these are often not resetable. -Press the (A) button to execute the underlying command. - -Comments are there just to help you. When pressing the (A) button, the entire text will be displayed +The different kinds of widgets are Numbers, On-Off-Switches, Text, Lists, Buttons and Comments. + +Number values can be changed using the left and right dpad buttons. To enter a value using the +keyboard, use the (A) button. To increase the step size multiplier, press the right stick button. + +On-off-Switches can be either enabled or disabled by selecting them and pressing the (A) button. + +Text values allow you to enter your own text using the keyboard. Press the (A) button to open it. + +Lists allow you to choose from a preselected list of values to set the value to. Press the (A) button +to open the list and press the (A) button again to confirm your choice. + +Buttons allow for custom one-time options to be executed. Be aware that these are often not resetable. +Press the (A) button to execute the underlying command. + +Comments are there just to help you. When pressing the (A) button, the entire text will be displayed in a popup window. \ No newline at end of file diff --git a/romfs/guide/2/6/config.json b/romfs/guide/2/6/config.json index 36a8909e..04432ffe 100644 --- a/romfs/guide/2/6/config.json +++ b/romfs/guide/2/6/config.json @@ -1,20 +1,20 @@ -{ - "images" : [ - { - "title" : "", - "path" : "banner.bin", - "x" : 0, - "y" : 142, - "w" : 1280, - "h" : 256 - } - ], - "text" : [ - { - "title" : "Introduction", - "path" : "text.txt", - "x" : 50, - "y" : 410 - } - ] +{ + "images" : [ + { + "title" : "", + "path" : "banner.bin", + "x" : 0, + "y" : 142, + "w" : 1280, + "h" : 256 + } + ], + "text" : [ + { + "title" : "Introduction", + "path" : "text.txt", + "x" : 50, + "y" : 410 + } + ] } \ No newline at end of file diff --git a/romfs/guide/2/6/text.txt b/romfs/guide/2/6/text.txt index 4c7d6085..9648c2f1 100644 --- a/romfs/guide/2/6/text.txt +++ b/romfs/guide/2/6/text.txt @@ -1,6 +1,6 @@ -EdiZon features a integrated and easily expandable save file editor based on user-made script files. -At this time more than thirty different games are supported and can be edited at any time without -the need for a computer. The most noticable ones include The Legend of Zelda: Breath of the Wild, -Super Mario Odyssey, Super Smash Bros Ultimate and New Super Mario Bros. U Deluxe. - +EdiZon features a integrated and easily expandable save file editor based on user-made script files. +At this time more than thirty different games are supported and can be edited at any time without +the need for a computer. The most noticable ones include The Legend of Zelda: Breath of the Wild, +Super Mario Odyssey, Super Smash Bros Ultimate and New Super Mario Bros. U Deluxe. + Thanks a lot to the awesome community who developed all of these scripts! \ No newline at end of file diff --git a/romfs/guide/2/7/config.json b/romfs/guide/2/7/config.json index 33177cc5..c52b689a 100644 --- a/romfs/guide/2/7/config.json +++ b/romfs/guide/2/7/config.json @@ -1,12 +1,12 @@ -{ - "images" : [ - ], - "text" : [ - { - "title" : "How do I edit my save files?", - "path" : "text.txt", - "x" : 50, - "y" : 100 - } - ] +{ + "images" : [ + ], + "text" : [ + { + "title" : "How do I edit my save files?", + "path" : "text.txt", + "x" : 50, + "y" : 100 + } + ] } \ No newline at end of file diff --git a/romfs/guide/2/7/text.txt b/romfs/guide/2/7/text.txt index 20f4129f..82ac3450 100644 --- a/romfs/guide/2/7/text.txt +++ b/romfs/guide/2/7/text.txt @@ -1,10 +1,10 @@ -For a game save file to be editable, somebody has to make a config/script for it. If you're -lucky and your game is supported, editing it is very straight forward. - -First of all to find out which ones of your currently installed games are editable, press the -(ZL) button in the EdiZon main menu. In this mode only games that have a config installed will -get shown. To edit a save file now, select the game in this list as if you wanted to backup it's -save file. In the new menu, press the (-) button and select the save file you want to edit. -The editor will now pop up where you can edit all the values shown to you. - +For a game save file to be editable, somebody has to make a config/script for it. If you're +lucky and your game is supported, editing it is very straight forward. + +First of all to find out which ones of your currently installed games are editable, press the +(ZL) button in the EdiZon main menu. In this mode only games that have a config installed will +get shown. To edit a save file now, select the game in this list as if you wanted to backup it's +save file. In the new menu, press the (-) button and select the save file you want to edit. +The editor will now pop up where you can edit all the values shown to you. + Make your changes and once you're done, press the (X) button to apply the changed values. \ No newline at end of file diff --git a/romfs/guide/2/8/config.json b/romfs/guide/2/8/config.json index da85fc3c..6d8cd6ba 100644 --- a/romfs/guide/2/8/config.json +++ b/romfs/guide/2/8/config.json @@ -1,23 +1,23 @@ -{ - "images" : [ - { - "title" : "Save file selection", - "path" : "editor1.bin", - "x" : 100, - "y" : 216, - "w" : 512, - "h" : 288 - }, - { - "title" : "Editor screen", - "path" : "editor2.bin", - "x" : 668, - "y" : 216, - "w" : 512, - "h" : 288 - } - ], - "text" : [ - - ] +{ + "images" : [ + { + "title" : "Save file selection", + "path" : "editor1.bin", + "x" : 100, + "y" : 216, + "w" : 512, + "h" : 288 + }, + { + "title" : "Editor screen", + "path" : "editor2.bin", + "x" : 668, + "y" : 216, + "w" : 512, + "h" : 288 + } + ], + "text" : [ + + ] } \ No newline at end of file diff --git a/romfs/guide/2/9/config.json b/romfs/guide/2/9/config.json index 9586032c..511dbe2d 100644 --- a/romfs/guide/2/9/config.json +++ b/romfs/guide/2/9/config.json @@ -1,23 +1,23 @@ -{ - "images" : [ - { - "title" : "Edited save file values", - "path" : "editor1.bin", - "x" : 100, - "y" : 216, - "w" : 512, - "h" : 288 - }, - { - "title" : "Inject changes", - "path" : "editor2.bin", - "x" : 668, - "y" : 216, - "w" : 512, - "h" : 288 - } - ], - "text" : [ - - ] +{ + "images" : [ + { + "title" : "Edited save file values", + "path" : "editor1.bin", + "x" : 100, + "y" : 216, + "w" : 512, + "h" : 288 + }, + { + "title" : "Inject changes", + "path" : "editor2.bin", + "x" : 668, + "y" : 216, + "w" : 512, + "h" : 288 + } + ], + "text" : [ + + ] } \ No newline at end of file diff --git a/source/guis/gui.cpp b/source/guis/gui.cpp index 8f0b4ee1..ce0b339f 100644 --- a/source/guis/gui.cpp +++ b/source/guis/gui.cpp @@ -1,707 +1,707 @@ -#include "guis/gui.hpp" - -#include -#include - -static float menuTimer = 0.0F; -static u32 stride; - -Gui::Gui() { - Gui::g_currSnackbar = nullptr; - Gui::g_currListSelector = nullptr; - Gui::g_currMessageBox = nullptr; - - m_fontLibret = 1; - m_fontFacesTotal = 0; - - fontInit(); -} - -Gui::~Gui() { - Gui::g_currSnackbar = nullptr; - Gui::g_currListSelector = nullptr; - Gui::g_currMessageBox = nullptr; - - fontExit(); -} - -void Gui::update() { - menuTimer += 0.005; - - if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->update(); - - if (Gui::g_currSnackbar != nullptr) { - Gui::g_currSnackbar->update(); - - if (Gui::g_currSnackbar->isDead()) { - delete Gui::g_currSnackbar; - Gui::g_currSnackbar = nullptr; - } - } - - float highlightMultiplier = (sin(menuTimer) + 1) / 2.0F; - currTheme.highlightColor.r = 0x27 + 0x61 * highlightMultiplier; - currTheme.highlightColor.g = 0xA3 + 0x4F * highlightMultiplier; - currTheme.highlightColor.b = 0xC7 + 0x29 * highlightMultiplier; - currTheme.highlightColor.a = 0xC0 + 0x3F * ((highlightMultiplier * 2) - 1); -} - -inline u8 Gui::blendColor(u32 src, u32 dst, u8 alpha) { - u8 one_minus_alpha = static_cast(255) - alpha; - return (dst*alpha + src*one_minus_alpha) / static_cast(255); -} - -color_t Gui::makeColor(u8 r, u8 g, u8 b, u8 a) { - color_t clr; - clr.r = r; - clr.g = g; - clr.b = b; - clr.a = a; - - return clr; -} - -inline void Gui::drawPixel(s16 x, s16 y, color_t clr) { - if (x >= 1280 || y >= 720 || x < 0 || y < 0) - return; - - u32 off = y * stride + x * 4; - framebuffer[off] = blendColor(framebuffer[off], clr.r, clr.a); off++; - framebuffer[off] = blendColor(framebuffer[off], clr.g, clr.a); off++; - framebuffer[off] = blendColor(framebuffer[off], clr.b, clr.a); off++; - framebuffer[off] = 0xFF; -} - -inline void Gui::draw4PixelsRaw(s16 x, s16 y, color_t clr) { - if (x >= 1280 || y >= 720 || x > 1280-4 || x < 0 || y < 0) - return; - - u32 color = clr.r | (clr.g<<8) | (clr.b<<16) | (0xff<<24); - u128 val = color | ((u128)color<<32) | ((u128)color<<64) | ((u128)color<<96); - u32 off = y * stride + x * 4; - *((u128*)&framebuffer[off]) = val; -} - -bool Gui::fontInit() { - FT_Error ret = 0; - - for (u32 i = 0; i < FONT_FACES_MAX; i++) m_fontFacesRet[i] = 1; - - ret = FT_Init_FreeType(&m_fontLibrary); - m_fontLibret = ret; - if (m_fontLibret) return false; - - PlFontData fonts[PlSharedFontType_Total]; - - if (R_FAILED(plGetSharedFont(0, fonts, FONT_FACES_MAX, &m_fontFacesTotal))) return false; - - for (u32 i = 0; i < m_fontFacesTotal; i++) { - ret = FT_New_Memory_Face(m_fontLibrary, (FT_Byte*)fonts[i].address, fonts[i].size, 0, &m_fontFaces[i]); - - m_fontFacesRet[i] = ret; - if (ret) return false; - } - - return true; -} - -void Gui::fontExit() { - for (u32 i = 0; i < m_fontFacesTotal; i++) - if (m_fontFacesRet[i] == 0) FT_Done_Face(m_fontFaces[i]); - - if (m_fontLibret == 0) FT_Done_FreeType(m_fontLibrary); -} - -bool Gui::setFontType(u32 font) { - u32 scale = 0; - FT_Error ret = 0; - - switch (font) { - case font14: scale = 4; break; - case font20: scale = 6; break; - case font24: scale = 7; break; - case fontTitle: scale = 10; break; - case fontHuge: scale = 20; break; - default: return false; - } - - for (u32 i = 0; i < m_fontFacesTotal; i++) { - ret = FT_Set_Char_Size(m_fontFaces[i], 0, scale * 64, 300, 300); - - if (ret) return false; - } - - return true; -} - -inline bool Gui::fontLoadGlyph(glyph_t* glyph, u32 font, u32 codepoint) { - FT_Face face; - FT_Error ret = 0; - FT_GlyphSlot slot; - FT_UInt glyphIndex; - FT_Bitmap *bitmap; - - if (m_fontFacesTotal == 0) return false; - - for (u32 i = 0; i < m_fontFacesTotal; i++) { - face = m_fontFaces[i]; - m_fontLastUsedFace = face; - glyphIndex = FT_Get_Char_Index(face, codepoint); - - if (glyphIndex == 0) continue; - - ret = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT); - - if (ret==0) - ret = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); - - if (ret) return false; - - break; - } - - slot = face->glyph; - bitmap = &slot->bitmap; - - glyph->width = bitmap->width; - glyph->height = bitmap->rows; - glyph->pitch = bitmap->pitch; - glyph->data = bitmap->buffer; - glyph->advance = slot->advance.x >> 6; - glyph->posX = slot->bitmap_left; - glyph->posY = slot->bitmap_top; - - return true; -} - -void Gui::drawGlyph(s16 x, s16 y, color_t clr, const glyph_t* glyph) { - const u8* data = glyph->data; - x += glyph->posX; - y -= glyph->posY; - - for (u32 j = 0; j < glyph->height; j++) { - for (u32 i = 0; i < glyph->width; i++) { - color_t pixelColor = clr; - pixelColor.a = data[i] * (static_cast(clr.a) / 0xFF); - if (!pixelColor.a) continue; - drawPixel(x+i, y+j, pixelColor); - } - data += glyph->pitch; - } -} - -inline u8 Gui::decodeByte(const char** ptr) { - u8 c = static_cast(**ptr); - (*ptr)++; - - return c; -} - -// UTF-8 code adapted from http://www.json.org/JSON_checker/utf8_decode.c - -inline s8 Gui::decodeUTF8Cont(const char** ptr) { - s32 c = decodeByte(ptr); - return ((c & 0xC0) == 0x80) ? (c & 0x3F) : -1; -} - -inline u32 Gui::decodeUTF8(const char** ptr) { - u32 r; - u8 c; - s8 c1, c2, c3; - - c = decodeByte(ptr); - - if ((c & 0x80) == 0) - return c; - - if ((c & 0xE0) == 0xC0) { - c1 = decodeUTF8Cont(ptr); - if (c1 >= 0) { - r = ((c & 0x1F) << 6) | c1; - if (r >= 0x80) - return r; - } - } else if ((c & 0xF0) == 0xE0) { - c1 = decodeUTF8Cont(ptr); - if (c1 >= 0) { - c2 = decodeUTF8Cont(ptr); - if (c2 >= 0) { - r = ((c & 0x0F) << 12) | (c1 << 6) | c2; - if (r >= 0x800 && (r < 0xD800 || r >= 0xE000)) - return r; - } - } - } else if ((c & 0xF8) == 0xF0) { - c1 = decodeUTF8Cont(ptr); - if (c1 >= 0) { - c2 = decodeUTF8Cont(ptr); - if (c2 >= 0) { - c3 = decodeUTF8Cont(ptr); - if (c3 >= 0) { - r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; - if (r >= 0x10000 && r < 0x110000) - return r; - } - } - } - } - return 0xFFFD; -} - -void Gui::drawText_(u32 font, s16 x, s16 y, color_t clr, const char* text, s32 max_width, const char* end_text) { - u32 origX = x; - - if (m_fontFacesTotal == 0) return; - if (!setFontType(font)) return; - m_fontLastUsedFace = m_fontFaces[0]; - - switch (font) { - case font14: y += 20; break; - case font20: y += 26; break; - case font24: y += 35; break; - } - - if (text == nullptr) return; - - while (*text) { - if (max_width && x - origX >= static_cast(max_width)) { - text = end_text; - max_width = 0; - } - - glyph_t glyph; - uint32_t codepoint = decodeUTF8(&text); - - if (codepoint == '\n') { - if (max_width) { - text = end_text; - max_width = 0; - continue; - } - - x = origX; - - continue; - } - - if (!fontLoadGlyph(&glyph, font, codepoint)) { - if (!fontLoadGlyph(&glyph, font, '?')) - continue; - } - drawGlyph(x, y, clr, &glyph); - x += glyph.advance; - } -} - -void Gui::drawText(u32 font, s16 x, s16 y, color_t clr, const char* text) { - drawText_(font, x, y, clr, text, 0, nullptr); -} - -std::vector Gui::split(const std::string& s, const char& c) { - std::string buff {""}; - std::vector v; - - for(auto n:s) { - if (n != c) buff += n; - else if (n == c && buff != "") { - v.push_back(buff); - buff = ""; - } - } - - if(buff != "") - v.push_back(buff); - - return v; -} - -void Gui::drawTextAligned(u32 font, s16 x, s16 y, color_t clr, const char* text, TextAlignment alignment) { - u32 textWidth, textHeight; - std::vector lines; - - std::hash hashFn; - - switch (alignment) { - case ALIGNED_LEFT: - lines = Gui::split(text, '\n'); - - for (auto line : lines) { - size_t strHash = hashFn(std::string(line)); - - if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { - getTextDimensions(font, line.c_str(), &textWidth, &textHeight); - m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); - } - - drawText_(font, x, y, clr, line.c_str(), 0, nullptr); - y += m_stringDimensions[strHash].second; - - } - break; - case ALIGNED_CENTER: - lines = Gui::split(text, '\n'); - - for (auto line : lines) { - size_t strHash = hashFn(std::string(line)); - - if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { - getTextDimensions(font, line.c_str(), &textWidth, &textHeight); - m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); - } - - drawText_(font, x - (m_stringDimensions[strHash].first / 2.0F), y, clr, line.c_str(), 0, nullptr); - y += m_stringDimensions[strHash].second; - } - break; - case ALIGNED_RIGHT: - lines = Gui::split(text, '\n'); - - for (auto line : lines) { - size_t strHash = hashFn(std::string(line)); - - if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { - getTextDimensions(font, line.c_str(), &textWidth, &textHeight); - m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); - } - - drawText_(font, x - m_stringDimensions[strHash].first, y, clr, line.c_str(), 0, nullptr); - y += m_stringDimensions[strHash].second; - } - break; - - } -} - -void Gui::drawTextTruncate(u32 font, s16 x, s16 y, color_t clr, const char* text, u32 max_width, const char* end_text) { - drawText_(font, x, y, clr, text, max_width, end_text); -} - -void Gui::getTextDimensions(u32 font, const char* text, u32* width_out, u32* height_out) { - u32 x = 0; - u32 width = 0, height = 0; - - if (m_fontFacesTotal == 0) return; - if (!setFontType(font)) return; - m_fontLastUsedFace = m_fontFaces[0]; - - while (*text) { - glyph_t glyph; - u32 codepoint = decodeUTF8(&text); - - //if (codepoint >= 0x0001 && codepoint <=) - - if (codepoint == '\n') { - x = 0; - height += m_fontLastUsedFace->size->metrics.height >> 6; - continue; - } - - - - if (!fontLoadGlyph(&glyph, font, codepoint)) { - if (!fontLoadGlyph(&glyph, font, '?')) - continue; - } - - x += glyph.advance; - - if (x > width) - width = x; - } - height += m_fontLastUsedFace->size->metrics.height >> 6; - - if (width_out != nullptr) - *width_out = width; - - if (height_out != nullptr) - *height_out = height; -} - -void Gui::drawImage(s16 x, s16 y, s16 width, s16 height, const u8 *image, ImageMode mode) { - s32 tmpx, tmpy; - s32 pos; - color_t current_color; - - if (image == nullptr) return; - - for (tmpy = 0; tmpy < height; tmpy++) { - for (tmpx = 0; tmpx < width; tmpx++) { - switch (mode) { - case IMAGE_MODE_RGB24: - pos = ((tmpy*width) + tmpx) * 3; - current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], 255); - break; - case IMAGE_MODE_RGBA32: - pos = ((tmpy*width) + tmpx) * 4; - current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]); - break; - case IMAGE_MODE_BGR24: - pos = ((tmpy*width) + tmpx) * 3; - current_color = makeColor(image[pos+2], image[pos+1], image[pos+0], 255); - break; - case IMAGE_MODE_ABGR32: - pos = ((tmpy*width) + tmpx) * 4; - current_color = makeColor(image[pos+3], image[pos+2], image[pos+1], image[pos+0]); - break; - } - - drawPixel(x+tmpx, y+tmpy, current_color); - } - } -} - -void Gui::drawImage(s16 x, s16 y, s16 startx, s16 starty, s16 width, s16 height, const u8 *image, ImageMode mode) { - s32 tmpx, tmpy; - s32 pos; - color_t current_color; - - if (image == nullptr) return; - - for (tmpy = startx; tmpy < height; tmpy++) { - for (tmpx = starty; tmpx < width; tmpx++) { - switch (mode) { - case IMAGE_MODE_RGB24: - pos = ((tmpy*width) + tmpx) * 3; - current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], 255); - break; - case IMAGE_MODE_RGBA32: - pos = ((tmpy*width) + tmpx) * 4; - current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]); - break; - case IMAGE_MODE_BGR24: - pos = ((tmpy*width) + tmpx) * 3; - current_color = makeColor(image[pos+2], image[pos+1], image[pos+0], 255); - break; - case IMAGE_MODE_ABGR32: - pos = ((tmpy*width) + tmpx) * 4; - current_color = makeColor(image[pos+3], image[pos+2], image[pos+1], image[pos+0]); - break; - } - - drawPixel(x+tmpx, y+tmpy, current_color); - } - } -} - -void Gui::drawRectangled(s16 x, s16 y, s16 w, s16 h, color_t color) { - for (s32 j = y; j < y + h; j++) { - for (s32 i = x; i < x + w; i++) { - drawPixel(i, j, color); - } - } -} - -void Gui::drawRectangle(s16 x, s16 y, s16 w, s16 h, color_t color) { - for (s32 j = y; j < y + h; j++) { - for (s32 i = x; i < x + w; i+=4) { - draw4PixelsRaw(i, j, color); - } - } -} - -void Gui::drawShadow(s16 x, s16 y, s16 width, s16 height) { - color_t shadowColor; - u8 shadowAlphaBase = 80; - u8 shadowSize = 4; - u8 shadowInset; - - y += height; - - for (s32 tmpx = x; tmpx < (x + width); tmpx+=4) { - for (s32 tmpy = y; tmpy < (y + height); tmpy++) { - shadowColor = makeColor(0, 0, 0, shadowAlphaBase * (1.0F - static_cast(tmpy - y) / (static_cast(shadowSize)))); - shadowInset = (tmpy - y); - - if (tmpx >= (x + shadowInset) && tmpx < (x + width - shadowInset)) - for (s32 i = 0; i < 4; i++) { - if (tmpx < 0 || tmpy < 0) continue; - drawPixel(tmpx + i,tmpy, shadowColor); - } - } - } -} - -void Gui::drawTooltip(s16 x, s16 y, const char *text, color_t backgroundColor, color_t textColor, u8 alpha, bool flipped) { - backgroundColor.a = alpha; - textColor.a = alpha; - - s16 tipX, tipY; - for (tipY = 0; tipY < 10; tipY++) { - for (tipX = x - tipY; tipX < x + tipY; tipX++) { - if(tipX >= 0 && tipX < 1280 && tipY >= 0 && tipY <= 1280) - Gui::drawPixel(tipX, (flipped ? -tipY : tipY) + y, backgroundColor); - else continue; - } - } - - tipY += y; - - u32 textWidth, textHeight; - Gui::getTextDimensions(font20, text, &textWidth, &textHeight); - - s16 overlapRight = std::max(static_cast((tipX + textWidth - 20)) - 1280, 0); - s16 overlapLeft = std::min(tipX - 50 - overlapRight, 0); - - Gui::drawRectangled(tipX - 50 - overlapRight - overlapLeft, flipped ? tipY - textHeight - 49 : tipY, textWidth + 30, textHeight + 30, backgroundColor); - Gui::drawTextAligned(font20, tipX - 35 + static_cast(textWidth) / 2 - overlapRight - overlapLeft, flipped ? tipY - textHeight - 39 : tipY + 10, textColor, text, ALIGNED_CENTER); -} - -inline u8 getPixel(u8* in, size_t src_width, size_t src_height, u16 x, u16 y, s32 channel) { - if (x < src_width && y < src_height) - return in[(x * 3 * src_width) + (3 * y) + channel]; - - return 0; -} - -void Gui::resizeImage(u8* in, u8* out, size_t src_width, size_t src_height, size_t dest_width, size_t dest_height) { - const float tx = static_cast(src_width) / dest_width; - const float ty = static_cast(src_height) / dest_height; - const s32 channels = 3; - const size_t row_stride = dest_width * channels; - - u8 C[5] = { 0 }; - - for (u32 i = 0; i < dest_height; ++i) { - for (u32 j = 0; j < dest_width; ++j) { - const s32 x = static_cast(tx * j); - const s32 y = static_cast(ty * i); - const float dx = tx * j - x; - const float dy = ty * i - y; - - for (s32 k = 0; k < 3; ++k) { - for (s32 jj = 0; jj < 4; ++jj) { - const s32 z = y - 1 + jj; - - u8 a0 = getPixel(in, src_width, src_height, z, x, k); - u8 d0 = getPixel(in, src_width, src_height, z, x - 1, k) - a0; - u8 d2 = getPixel(in, src_width, src_height, z, x + 1, k) - a0; - u8 d3 = getPixel(in, src_width, src_height, z, x + 2, k) - a0; - u8 a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; - u8 a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; - u8 a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; - C[jj] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx; - - d0 = C[0] - C[1]; - d2 = C[2] - C[1]; - d3 = C[3] - C[1]; - a0 = C[1]; - a1 = -1.0 / 3 * d0 + d2 -1.0 / 6 * d3; - a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; - a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; - out[i * row_stride + j * channels + k] = a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy; - } - } - } - } -} - -bool Gui::requestKeyboardInput(std::string headerText, std::string subHeaderText, std::string initialText, SwkbdType type, char *out_text, size_t maxLength) { - SwkbdConfig kbd; - swkbdCreate(&kbd, 0); - swkbdConfigMakePresetDefault(&kbd); - - swkbdConfigSetInitialText(&kbd, initialText.c_str()); - swkbdConfigSetHeaderText(&kbd, headerText.c_str()); - swkbdConfigSetSubText(&kbd, subHeaderText.c_str()); - - kbd.arg.arg.arg.leftButtonText = '.'; - kbd.arg.arg.arg.rightButtonText = '-'; - kbd.arg.arg.arg.stringLenMax = maxLength; - kbd.arg.arg.arg.stringLenMaxExt = 1; - kbd.arg.arg.arg.textDrawType = SwkbdTextDrawType_Line; - kbd.arg.arg.arg.returnButtonFlag = false; - kbd.arg.arg.arg.type = type; - kbd.arg.arg.arg.keySetDisableBitmask = SwkbdKeyDisableBitmask_At | SwkbdKeyDisableBitmask_Percent | SwkbdKeyDisableBitmask_ForwardSlash | SwkbdKeyDisableBitmask_Backslash; - - swkbdShow(&kbd, out_text, maxLength + 1); - swkbdClose(&kbd); - - return std::strcmp(out_text, "") != 0; -} - -u128 Gui::requestPlayerSelection() { - struct UserReturnData{ - u64 result; - u128 UID; - } PACKED; - - struct UserReturnData outdata; - - AppletHolder aph; - AppletStorage ast; - AppletStorage hast1; - LibAppletArgs args; - - u8 indata[0xA0] = { 0 }; - indata[0x96] = 1; - - appletCreateLibraryApplet(&aph, AppletId_playerSelect, LibAppletMode_AllForeground); - libappletArgsCreate(&args, 0); - libappletArgsPush(&args, &aph); - - appletCreateStorage(&hast1, 0xA0); - - appletStorageWrite(&hast1, 0, indata, 0xA0); - appletHolderPushInData(&aph, &hast1); - appletHolderStart(&aph); - - while (appletHolderWaitInteractiveOut(&aph)); - - appletHolderJoin(&aph); - appletHolderPopOutData(&aph, &ast); - appletStorageRead(&ast, 0, &outdata, 24); - - appletHolderClose(&aph); - appletStorageClose(&ast); - appletStorageClose(&hast1); - - return outdata.UID; -} - -void Gui::requestErrorMessage(Result result) { - AppletHolder aph; - AppletStorage ast; - AppletStorage hast1; - LibAppletArgs args; - u8 indata[20] = { 0 }; - - *(Result*)&indata[16] = result; - - appletCreateLibraryApplet(&aph, AppletId_error, LibAppletMode_AllForeground); - libappletArgsCreate(&args, 0); - libappletArgsPush(&args, &aph); - - appletCreateStorage(&hast1, 20); - - appletStorageWrite(&hast1, 0, indata, 20); - appletHolderPushInData(&aph, &hast1); - - appletHolderStart(&aph); - - while (appletHolderWaitInteractiveOut(&aph)); - - appletHolderJoin(&aph); - appletHolderPopOutData(&aph, &ast); - - appletHolderClose(&aph); - appletStorageClose(&ast); - appletStorageClose(&hast1); -} - -void Gui::beginDraw() { - this->framebuffer = (u8*)framebufferBegin(&Gui::g_fb_obj, &stride); -} - -void Gui::endDraw() { - if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->draw(this); - - if (Gui::g_currSnackbar != nullptr) - Gui::g_currSnackbar->draw(this); - - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->draw(this); - - framebufferEnd(&Gui::g_fb_obj); -} +#include "guis/gui.hpp" + +#include +#include + +static float menuTimer = 0.0F; +static u32 stride; + +Gui::Gui() { + Gui::g_currSnackbar = nullptr; + Gui::g_currListSelector = nullptr; + Gui::g_currMessageBox = nullptr; + + m_fontLibret = 1; + m_fontFacesTotal = 0; + + fontInit(); +} + +Gui::~Gui() { + Gui::g_currSnackbar = nullptr; + Gui::g_currListSelector = nullptr; + Gui::g_currMessageBox = nullptr; + + fontExit(); +} + +void Gui::update() { + menuTimer += 0.005; + + if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->update(); + + if (Gui::g_currSnackbar != nullptr) { + Gui::g_currSnackbar->update(); + + if (Gui::g_currSnackbar->isDead()) { + delete Gui::g_currSnackbar; + Gui::g_currSnackbar = nullptr; + } + } + + float highlightMultiplier = (sin(menuTimer) + 1) / 2.0F; + currTheme.highlightColor.r = 0x27 + 0x61 * highlightMultiplier; + currTheme.highlightColor.g = 0xA3 + 0x4F * highlightMultiplier; + currTheme.highlightColor.b = 0xC7 + 0x29 * highlightMultiplier; + currTheme.highlightColor.a = 0xC0 + 0x3F * ((highlightMultiplier * 2) - 1); +} + +inline u8 Gui::blendColor(u32 src, u32 dst, u8 alpha) { + u8 one_minus_alpha = static_cast(255) - alpha; + return (dst*alpha + src*one_minus_alpha) / static_cast(255); +} + +color_t Gui::makeColor(u8 r, u8 g, u8 b, u8 a) { + color_t clr; + clr.r = r; + clr.g = g; + clr.b = b; + clr.a = a; + + return clr; +} + +inline void Gui::drawPixel(s16 x, s16 y, color_t clr) { + if (x >= 1280 || y >= 720 || x < 0 || y < 0) + return; + + u32 off = y * stride + x * 4; + framebuffer[off] = blendColor(framebuffer[off], clr.r, clr.a); off++; + framebuffer[off] = blendColor(framebuffer[off], clr.g, clr.a); off++; + framebuffer[off] = blendColor(framebuffer[off], clr.b, clr.a); off++; + framebuffer[off] = 0xFF; +} + +inline void Gui::draw4PixelsRaw(s16 x, s16 y, color_t clr) { + if (x >= 1280 || y >= 720 || x > 1280-4 || x < 0 || y < 0) + return; + + u32 color = clr.r | (clr.g<<8) | (clr.b<<16) | (0xff<<24); + u128 val = color | ((u128)color<<32) | ((u128)color<<64) | ((u128)color<<96); + u32 off = y * stride + x * 4; + *((u128*)&framebuffer[off]) = val; +} + +bool Gui::fontInit() { + FT_Error ret = 0; + + for (u32 i = 0; i < FONT_FACES_MAX; i++) m_fontFacesRet[i] = 1; + + ret = FT_Init_FreeType(&m_fontLibrary); + m_fontLibret = ret; + if (m_fontLibret) return false; + + PlFontData fonts[PlSharedFontType_Total]; + + if (R_FAILED(plGetSharedFont(0, fonts, FONT_FACES_MAX, &m_fontFacesTotal))) return false; + + for (u32 i = 0; i < m_fontFacesTotal; i++) { + ret = FT_New_Memory_Face(m_fontLibrary, (FT_Byte*)fonts[i].address, fonts[i].size, 0, &m_fontFaces[i]); + + m_fontFacesRet[i] = ret; + if (ret) return false; + } + + return true; +} + +void Gui::fontExit() { + for (u32 i = 0; i < m_fontFacesTotal; i++) + if (m_fontFacesRet[i] == 0) FT_Done_Face(m_fontFaces[i]); + + if (m_fontLibret == 0) FT_Done_FreeType(m_fontLibrary); +} + +bool Gui::setFontType(u32 font) { + u32 scale = 0; + FT_Error ret = 0; + + switch (font) { + case font14: scale = 4; break; + case font20: scale = 6; break; + case font24: scale = 7; break; + case fontTitle: scale = 10; break; + case fontHuge: scale = 20; break; + default: return false; + } + + for (u32 i = 0; i < m_fontFacesTotal; i++) { + ret = FT_Set_Char_Size(m_fontFaces[i], 0, scale * 64, 300, 300); + + if (ret) return false; + } + + return true; +} + +inline bool Gui::fontLoadGlyph(glyph_t* glyph, u32 font, u32 codepoint) { + FT_Face face; + FT_Error ret = 0; + FT_GlyphSlot slot; + FT_UInt glyphIndex; + FT_Bitmap *bitmap; + + if (m_fontFacesTotal == 0) return false; + + for (u32 i = 0; i < m_fontFacesTotal; i++) { + face = m_fontFaces[i]; + m_fontLastUsedFace = face; + glyphIndex = FT_Get_Char_Index(face, codepoint); + + if (glyphIndex == 0) continue; + + ret = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT); + + if (ret==0) + ret = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + + if (ret) return false; + + break; + } + + slot = face->glyph; + bitmap = &slot->bitmap; + + glyph->width = bitmap->width; + glyph->height = bitmap->rows; + glyph->pitch = bitmap->pitch; + glyph->data = bitmap->buffer; + glyph->advance = slot->advance.x >> 6; + glyph->posX = slot->bitmap_left; + glyph->posY = slot->bitmap_top; + + return true; +} + +void Gui::drawGlyph(s16 x, s16 y, color_t clr, const glyph_t* glyph) { + const u8* data = glyph->data; + x += glyph->posX; + y -= glyph->posY; + + for (u32 j = 0; j < glyph->height; j++) { + for (u32 i = 0; i < glyph->width; i++) { + color_t pixelColor = clr; + pixelColor.a = data[i] * (static_cast(clr.a) / 0xFF); + if (!pixelColor.a) continue; + drawPixel(x+i, y+j, pixelColor); + } + data += glyph->pitch; + } +} + +inline u8 Gui::decodeByte(const char** ptr) { + u8 c = static_cast(**ptr); + (*ptr)++; + + return c; +} + +// UTF-8 code adapted from http://www.json.org/JSON_checker/utf8_decode.c + +inline s8 Gui::decodeUTF8Cont(const char** ptr) { + s32 c = decodeByte(ptr); + return ((c & 0xC0) == 0x80) ? (c & 0x3F) : -1; +} + +inline u32 Gui::decodeUTF8(const char** ptr) { + u32 r; + u8 c; + s8 c1, c2, c3; + + c = decodeByte(ptr); + + if ((c & 0x80) == 0) + return c; + + if ((c & 0xE0) == 0xC0) { + c1 = decodeUTF8Cont(ptr); + if (c1 >= 0) { + r = ((c & 0x1F) << 6) | c1; + if (r >= 0x80) + return r; + } + } else if ((c & 0xF0) == 0xE0) { + c1 = decodeUTF8Cont(ptr); + if (c1 >= 0) { + c2 = decodeUTF8Cont(ptr); + if (c2 >= 0) { + r = ((c & 0x0F) << 12) | (c1 << 6) | c2; + if (r >= 0x800 && (r < 0xD800 || r >= 0xE000)) + return r; + } + } + } else if ((c & 0xF8) == 0xF0) { + c1 = decodeUTF8Cont(ptr); + if (c1 >= 0) { + c2 = decodeUTF8Cont(ptr); + if (c2 >= 0) { + c3 = decodeUTF8Cont(ptr); + if (c3 >= 0) { + r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + if (r >= 0x10000 && r < 0x110000) + return r; + } + } + } + } + return 0xFFFD; +} + +void Gui::drawText_(u32 font, s16 x, s16 y, color_t clr, const char* text, s32 max_width, const char* end_text) { + u32 origX = x; + + if (m_fontFacesTotal == 0) return; + if (!setFontType(font)) return; + m_fontLastUsedFace = m_fontFaces[0]; + + switch (font) { + case font14: y += 20; break; + case font20: y += 26; break; + case font24: y += 35; break; + } + + if (text == nullptr) return; + + while (*text) { + if (max_width && x - origX >= static_cast(max_width)) { + text = end_text; + max_width = 0; + } + + glyph_t glyph; + uint32_t codepoint = decodeUTF8(&text); + + if (codepoint == '\n') { + if (max_width) { + text = end_text; + max_width = 0; + continue; + } + + x = origX; + + continue; + } + + if (!fontLoadGlyph(&glyph, font, codepoint)) { + if (!fontLoadGlyph(&glyph, font, '?')) + continue; + } + drawGlyph(x, y, clr, &glyph); + x += glyph.advance; + } +} + +void Gui::drawText(u32 font, s16 x, s16 y, color_t clr, const char* text) { + drawText_(font, x, y, clr, text, 0, nullptr); +} + +std::vector Gui::split(const std::string& s, const char& c) { + std::string buff {""}; + std::vector v; + + for(auto n:s) { + if (n != c) buff += n; + else if (n == c && buff != "") { + v.push_back(buff); + buff = ""; + } + } + + if(buff != "") + v.push_back(buff); + + return v; +} + +void Gui::drawTextAligned(u32 font, s16 x, s16 y, color_t clr, const char* text, TextAlignment alignment) { + u32 textWidth, textHeight; + std::vector lines; + + std::hash hashFn; + + switch (alignment) { + case ALIGNED_LEFT: + lines = Gui::split(text, '\n'); + + for (auto line : lines) { + size_t strHash = hashFn(std::string(line)); + + if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { + getTextDimensions(font, line.c_str(), &textWidth, &textHeight); + m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); + } + + drawText_(font, x, y, clr, line.c_str(), 0, nullptr); + y += m_stringDimensions[strHash].second; + + } + break; + case ALIGNED_CENTER: + lines = Gui::split(text, '\n'); + + for (auto line : lines) { + size_t strHash = hashFn(std::string(line)); + + if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { + getTextDimensions(font, line.c_str(), &textWidth, &textHeight); + m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); + } + + drawText_(font, x - (m_stringDimensions[strHash].first / 2.0F), y, clr, line.c_str(), 0, nullptr); + y += m_stringDimensions[strHash].second; + } + break; + case ALIGNED_RIGHT: + lines = Gui::split(text, '\n'); + + for (auto line : lines) { + size_t strHash = hashFn(std::string(line)); + + if (m_stringDimensions.find(strHash) == m_stringDimensions.end()) { + getTextDimensions(font, line.c_str(), &textWidth, &textHeight); + m_stringDimensions.insert(std::make_pair(strHash, std::pair(textWidth, textHeight))); + } + + drawText_(font, x - m_stringDimensions[strHash].first, y, clr, line.c_str(), 0, nullptr); + y += m_stringDimensions[strHash].second; + } + break; + + } +} + +void Gui::drawTextTruncate(u32 font, s16 x, s16 y, color_t clr, const char* text, u32 max_width, const char* end_text) { + drawText_(font, x, y, clr, text, max_width, end_text); +} + +void Gui::getTextDimensions(u32 font, const char* text, u32* width_out, u32* height_out) { + u32 x = 0; + u32 width = 0, height = 0; + + if (m_fontFacesTotal == 0) return; + if (!setFontType(font)) return; + m_fontLastUsedFace = m_fontFaces[0]; + + while (*text) { + glyph_t glyph; + u32 codepoint = decodeUTF8(&text); + + //if (codepoint >= 0x0001 && codepoint <=) + + if (codepoint == '\n') { + x = 0; + height += m_fontLastUsedFace->size->metrics.height >> 6; + continue; + } + + + + if (!fontLoadGlyph(&glyph, font, codepoint)) { + if (!fontLoadGlyph(&glyph, font, '?')) + continue; + } + + x += glyph.advance; + + if (x > width) + width = x; + } + height += m_fontLastUsedFace->size->metrics.height >> 6; + + if (width_out != nullptr) + *width_out = width; + + if (height_out != nullptr) + *height_out = height; +} + +void Gui::drawImage(s16 x, s16 y, s16 width, s16 height, const u8 *image, ImageMode mode) { + s32 tmpx, tmpy; + s32 pos; + color_t current_color; + + if (image == nullptr) return; + + for (tmpy = 0; tmpy < height; tmpy++) { + for (tmpx = 0; tmpx < width; tmpx++) { + switch (mode) { + case IMAGE_MODE_RGB24: + pos = ((tmpy*width) + tmpx) * 3; + current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], 255); + break; + case IMAGE_MODE_RGBA32: + pos = ((tmpy*width) + tmpx) * 4; + current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]); + break; + case IMAGE_MODE_BGR24: + pos = ((tmpy*width) + tmpx) * 3; + current_color = makeColor(image[pos+2], image[pos+1], image[pos+0], 255); + break; + case IMAGE_MODE_ABGR32: + pos = ((tmpy*width) + tmpx) * 4; + current_color = makeColor(image[pos+3], image[pos+2], image[pos+1], image[pos+0]); + break; + } + + drawPixel(x+tmpx, y+tmpy, current_color); + } + } +} + +void Gui::drawImage(s16 x, s16 y, s16 startx, s16 starty, s16 width, s16 height, const u8 *image, ImageMode mode) { + s32 tmpx, tmpy; + s32 pos; + color_t current_color; + + if (image == nullptr) return; + + for (tmpy = startx; tmpy < height; tmpy++) { + for (tmpx = starty; tmpx < width; tmpx++) { + switch (mode) { + case IMAGE_MODE_RGB24: + pos = ((tmpy*width) + tmpx) * 3; + current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], 255); + break; + case IMAGE_MODE_RGBA32: + pos = ((tmpy*width) + tmpx) * 4; + current_color = makeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]); + break; + case IMAGE_MODE_BGR24: + pos = ((tmpy*width) + tmpx) * 3; + current_color = makeColor(image[pos+2], image[pos+1], image[pos+0], 255); + break; + case IMAGE_MODE_ABGR32: + pos = ((tmpy*width) + tmpx) * 4; + current_color = makeColor(image[pos+3], image[pos+2], image[pos+1], image[pos+0]); + break; + } + + drawPixel(x+tmpx, y+tmpy, current_color); + } + } +} + +void Gui::drawRectangled(s16 x, s16 y, s16 w, s16 h, color_t color) { + for (s32 j = y; j < y + h; j++) { + for (s32 i = x; i < x + w; i++) { + drawPixel(i, j, color); + } + } +} + +void Gui::drawRectangle(s16 x, s16 y, s16 w, s16 h, color_t color) { + for (s32 j = y; j < y + h; j++) { + for (s32 i = x; i < x + w; i+=4) { + draw4PixelsRaw(i, j, color); + } + } +} + +void Gui::drawShadow(s16 x, s16 y, s16 width, s16 height) { + color_t shadowColor; + u8 shadowAlphaBase = 80; + u8 shadowSize = 4; + u8 shadowInset; + + y += height; + + for (s32 tmpx = x; tmpx < (x + width); tmpx+=4) { + for (s32 tmpy = y; tmpy < (y + height); tmpy++) { + shadowColor = makeColor(0, 0, 0, shadowAlphaBase * (1.0F - static_cast(tmpy - y) / (static_cast(shadowSize)))); + shadowInset = (tmpy - y); + + if (tmpx >= (x + shadowInset) && tmpx < (x + width - shadowInset)) + for (s32 i = 0; i < 4; i++) { + if (tmpx < 0 || tmpy < 0) continue; + drawPixel(tmpx + i,tmpy, shadowColor); + } + } + } +} + +void Gui::drawTooltip(s16 x, s16 y, const char *text, color_t backgroundColor, color_t textColor, u8 alpha, bool flipped) { + backgroundColor.a = alpha; + textColor.a = alpha; + + s16 tipX, tipY; + for (tipY = 0; tipY < 10; tipY++) { + for (tipX = x - tipY; tipX < x + tipY; tipX++) { + if(tipX >= 0 && tipX < 1280 && tipY >= 0 && tipY <= 1280) + Gui::drawPixel(tipX, (flipped ? -tipY : tipY) + y, backgroundColor); + else continue; + } + } + + tipY += y; + + u32 textWidth, textHeight; + Gui::getTextDimensions(font20, text, &textWidth, &textHeight); + + s16 overlapRight = std::max(static_cast((tipX + textWidth - 20)) - 1280, 0); + s16 overlapLeft = std::min(tipX - 50 - overlapRight, 0); + + Gui::drawRectangled(tipX - 50 - overlapRight - overlapLeft, flipped ? tipY - textHeight - 49 : tipY, textWidth + 30, textHeight + 30, backgroundColor); + Gui::drawTextAligned(font20, tipX - 35 + static_cast(textWidth) / 2 - overlapRight - overlapLeft, flipped ? tipY - textHeight - 39 : tipY + 10, textColor, text, ALIGNED_CENTER); +} + +inline u8 getPixel(u8* in, size_t src_width, size_t src_height, u16 x, u16 y, s32 channel) { + if (x < src_width && y < src_height) + return in[(x * 3 * src_width) + (3 * y) + channel]; + + return 0; +} + +void Gui::resizeImage(u8* in, u8* out, size_t src_width, size_t src_height, size_t dest_width, size_t dest_height) { + const float tx = static_cast(src_width) / dest_width; + const float ty = static_cast(src_height) / dest_height; + const s32 channels = 3; + const size_t row_stride = dest_width * channels; + + u8 C[5] = { 0 }; + + for (u32 i = 0; i < dest_height; ++i) { + for (u32 j = 0; j < dest_width; ++j) { + const s32 x = static_cast(tx * j); + const s32 y = static_cast(ty * i); + const float dx = tx * j - x; + const float dy = ty * i - y; + + for (s32 k = 0; k < 3; ++k) { + for (s32 jj = 0; jj < 4; ++jj) { + const s32 z = y - 1 + jj; + + u8 a0 = getPixel(in, src_width, src_height, z, x, k); + u8 d0 = getPixel(in, src_width, src_height, z, x - 1, k) - a0; + u8 d2 = getPixel(in, src_width, src_height, z, x + 1, k) - a0; + u8 d3 = getPixel(in, src_width, src_height, z, x + 2, k) - a0; + u8 a1 = -1.0 / 3 * d0 + d2 - 1.0 / 6 * d3; + u8 a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + u8 a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + C[jj] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx; + + d0 = C[0] - C[1]; + d2 = C[2] - C[1]; + d3 = C[3] - C[1]; + a0 = C[1]; + a1 = -1.0 / 3 * d0 + d2 -1.0 / 6 * d3; + a2 = 1.0 / 2 * d0 + 1.0 / 2 * d2; + a3 = -1.0 / 6 * d0 - 1.0 / 2 * d2 + 1.0 / 6 * d3; + out[i * row_stride + j * channels + k] = a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy; + } + } + } + } +} + +bool Gui::requestKeyboardInput(std::string headerText, std::string subHeaderText, std::string initialText, SwkbdType type, char *out_text, size_t maxLength) { + SwkbdConfig kbd; + swkbdCreate(&kbd, 0); + swkbdConfigMakePresetDefault(&kbd); + + swkbdConfigSetInitialText(&kbd, initialText.c_str()); + swkbdConfigSetHeaderText(&kbd, headerText.c_str()); + swkbdConfigSetSubText(&kbd, subHeaderText.c_str()); + + kbd.arg.arg.arg.leftButtonText = '.'; + kbd.arg.arg.arg.rightButtonText = '-'; + kbd.arg.arg.arg.stringLenMax = maxLength; + kbd.arg.arg.arg.stringLenMaxExt = 1; + kbd.arg.arg.arg.textDrawType = SwkbdTextDrawType_Line; + kbd.arg.arg.arg.returnButtonFlag = false; + kbd.arg.arg.arg.type = type; + kbd.arg.arg.arg.keySetDisableBitmask = SwkbdKeyDisableBitmask_At | SwkbdKeyDisableBitmask_Percent | SwkbdKeyDisableBitmask_ForwardSlash | SwkbdKeyDisableBitmask_Backslash; + + swkbdShow(&kbd, out_text, maxLength + 1); + swkbdClose(&kbd); + + return std::strcmp(out_text, "") != 0; +} + +u128 Gui::requestPlayerSelection() { + struct UserReturnData{ + u64 result; + u128 UID; + } PACKED; + + struct UserReturnData outdata; + + AppletHolder aph; + AppletStorage ast; + AppletStorage hast1; + LibAppletArgs args; + + u8 indata[0xA0] = { 0 }; + indata[0x96] = 1; + + appletCreateLibraryApplet(&aph, AppletId_playerSelect, LibAppletMode_AllForeground); + libappletArgsCreate(&args, 0); + libappletArgsPush(&args, &aph); + + appletCreateStorage(&hast1, 0xA0); + + appletStorageWrite(&hast1, 0, indata, 0xA0); + appletHolderPushInData(&aph, &hast1); + appletHolderStart(&aph); + + while (appletHolderWaitInteractiveOut(&aph)); + + appletHolderJoin(&aph); + appletHolderPopOutData(&aph, &ast); + appletStorageRead(&ast, 0, &outdata, 24); + + appletHolderClose(&aph); + appletStorageClose(&ast); + appletStorageClose(&hast1); + + return outdata.UID; +} + +void Gui::requestErrorMessage(Result result) { + AppletHolder aph; + AppletStorage ast; + AppletStorage hast1; + LibAppletArgs args; + u8 indata[20] = { 0 }; + + *(Result*)&indata[16] = result; + + appletCreateLibraryApplet(&aph, AppletId_error, LibAppletMode_AllForeground); + libappletArgsCreate(&args, 0); + libappletArgsPush(&args, &aph); + + appletCreateStorage(&hast1, 20); + + appletStorageWrite(&hast1, 0, indata, 20); + appletHolderPushInData(&aph, &hast1); + + appletHolderStart(&aph); + + while (appletHolderWaitInteractiveOut(&aph)); + + appletHolderJoin(&aph); + appletHolderPopOutData(&aph, &ast); + + appletHolderClose(&aph); + appletStorageClose(&ast); + appletStorageClose(&hast1); +} + +void Gui::beginDraw() { + this->framebuffer = (u8*)framebufferBegin(&Gui::g_fb_obj, &stride); +} + +void Gui::endDraw() { + if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->draw(this); + + if (Gui::g_currSnackbar != nullptr) + Gui::g_currSnackbar->draw(this); + + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->draw(this); + + framebufferEnd(&Gui::g_fb_obj); +} diff --git a/source/guis/gui_about.cpp b/source/guis/gui_about.cpp index e41890ac..cd1e817a 100644 --- a/source/guis/gui_about.cpp +++ b/source/guis/gui_about.cpp @@ -1,168 +1,168 @@ -#include "guis/gui_about.hpp" - -#include -#include - -#include "update_manager.hpp" -#include "helpers/util.h" -#include "helpers/config.hpp" - -static std::string remoteVersion, remoteCommitSha, remoteCommitMessage; -static Thread networkThread; -static bool threadRunning; -static bool updateAvailable; - -static void getVersionInfoAsync(void* args); - -GuiAbout::GuiAbout() : Gui() { - updateAvailable = false; - - remoteVersion = ""; - remoteCommitSha = ""; - remoteCommitMessage = ""; - - if (!threadRunning) { - threadRunning = true; - threadCreate(&networkThread, getVersionInfoAsync, nullptr, 0x2000, 0x2C, -2); - threadStart(&networkThread); - } -} - -GuiAbout::~GuiAbout() { - -} - -void GuiAbout::update() { - Gui::update(); -} - -void GuiAbout::draw() { - Gui::beginDraw(); - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 87, 1220, 1, currTheme.textColor); - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); - Gui::drawTextAligned(fontTitle, 70, 60, currTheme.textColor, "\uE017", ALIGNED_LEFT); - Gui::drawTextAligned(font24, 70, 23, currTheme.textColor, " About", ALIGNED_LEFT); - - if (updateAvailable) - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0F0 Install update \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - else - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - - Gui::drawTextAligned(fontHuge, 100, 180, Gui::makeColor(0xFB, 0xA6, 0x15, 0xFF), "EdiZon v" VERSION_STRING, ALIGNED_LEFT); - Gui::drawTextAligned(font20, 130, 190, currTheme.separatorColor, "by WerWolv", ALIGNED_LEFT); - - Gui::drawTextAligned(font14, 120, 250, currTheme.textColor, "Special thank to anybody who got involved into this project.", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 120, 270, currTheme.textColor, "Especially to all the config/cheat developers that brought this project to life!", ALIGNED_LEFT); - - Gui::drawTextAligned(font14, 900, 250, Gui::makeColor(0x51, 0x97, 0xF0, 0xFF), "Twitter: https://twitter.com/WerWolv", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 900, 275, Gui::makeColor(0x1A, 0x5E, 0xA7, 0xFF), "PayPal: https://werwolv.net/donate", ALIGNED_LEFT); - - - Gui::drawRectangled(50, 350, Gui::g_framebuffer_width - 100, 250, currTheme.textColor); - Gui::drawRectangled(51, 351, Gui::g_framebuffer_width - 102, updateAvailable ? 190 : 248, currTheme.backgroundColor); - Gui::drawShadow(52, 352, Gui::g_framebuffer_width - 104, 248); - - if (updateAvailable) - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 555, currTheme.backgroundColor, "A update for EdiZon, save editor or cheat is available!", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, 60, 360, currTheme.selectedColor, "EdiZon Update", ALIGNED_LEFT); - - Gui::drawTextAligned(font14, 80, 400, currTheme.textColor, std::string("Latest EdiZon version: " + (remoteVersion == "" ? "..." : remoteVersion)).c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font14, 80, 425, currTheme.textColor, std::string("Latest database commit: [ " + (remoteCommitSha == "" ? "..." : remoteCommitSha) + " ] ").c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font14, 90, 450, currTheme.separatorColor, (remoteCommitMessage == "" ? "..." : remoteCommitMessage.c_str()), ALIGNED_LEFT); - - Gui::endDraw(); -} - -void GuiAbout::onInput(u32 kdown) { - if (kdown & KEY_B) { - if (threadRunning) { - threadWaitForExit(&networkThread); - threadClose(&networkThread); - threadRunning = false; - } - - Gui::g_nextGui = GUI_MAIN; - } - - if (kdown & KEY_MINUS && updateAvailable) { - UpdateManager updateManager; - - (new MessageBox("Updating cheats, configs and EdiZon.\n \nThis may take a while...", MessageBox::NONE))->show(); - requestDraw(); - - Updates updates = updateManager.checkUpdate(); - - switch (updates) { - case NONE: (new MessageBox("Latest cheats and save editors are already installed!", MessageBox::OKAY))->show(); break; - case ERROR: (new MessageBox("An error while downloading the updates has occured!", MessageBox::OKAY))->show(); break; - case EDITOR: (new MessageBox("Updated save editors and cheats to the latest version!", MessageBox::OKAY))->show(); break; - case EDIZON: (new MessageBox("Updated EdiZon, save editors and cheats and \n scripts tothe latest version! \n Please restart EdiZon!", MessageBox::OKAY))->show(); break; - } - - if (updates == EDITOR || updates == EDIZON) { - memcpy(Config::getConfig()->latestCommit, remoteCommitSha.c_str(), remoteCommitSha.size()); - Config::writeConfig(); - } - - updateAvailable = (strcmp(remoteCommitSha.c_str(), Config::getConfig()->latestCommit) != 0 && strcmp(remoteCommitSha.c_str(), "???") != 0); - } -} - -void GuiAbout::onTouch(touchPosition &touch) { - -} - -void GuiAbout::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} - -static size_t writeToStr(const char * contents, size_t size, size_t nmemb, std::string * userp){ - auto totalBytes = (size * nmemb); - - userp->append(contents, totalBytes); - - return totalBytes; -} - -static void getVersionInfoAsync(void* args) { - CURL *curl = curl_easy_init(); - - struct curl_slist * headers = NULL; - headers = curl_slist_append(headers, "Cache-Control: no-cache"); - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_edizon.php"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteVersion); - - remoteVersion = ""; - if (curl_easy_perform(curl) != CURLE_OK) - remoteVersion = "???"; - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_db_sha.php"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteCommitSha); - - remoteCommitSha = ""; - - if (curl_easy_perform(curl) != CURLE_OK) - remoteCommitSha = "???"; - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_db_message.php"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteCommitMessage); - - remoteCommitMessage = ""; - - if (curl_easy_perform(curl) != CURLE_OK) - remoteCommitMessage = "???"; - - curl_easy_cleanup(curl); - - updateAvailable = (strcmp(remoteCommitSha.c_str(), Config::getConfig()->latestCommit) != 0 && strcmp(remoteCommitSha.c_str(), "???") != 0); -} +#include "guis/gui_about.hpp" + +#include +#include + +#include "update_manager.hpp" +#include "helpers/util.h" +#include "helpers/config.hpp" + +static std::string remoteVersion, remoteCommitSha, remoteCommitMessage; +static Thread networkThread; +static bool threadRunning; +static bool updateAvailable; + +static void getVersionInfoAsync(void* args); + +GuiAbout::GuiAbout() : Gui() { + updateAvailable = false; + + remoteVersion = ""; + remoteCommitSha = ""; + remoteCommitMessage = ""; + + if (!threadRunning) { + threadRunning = true; + threadCreate(&networkThread, getVersionInfoAsync, nullptr, 0x2000, 0x2C, -2); + threadStart(&networkThread); + } +} + +GuiAbout::~GuiAbout() { + +} + +void GuiAbout::update() { + Gui::update(); +} + +void GuiAbout::draw() { + Gui::beginDraw(); + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 87, 1220, 1, currTheme.textColor); + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); + Gui::drawTextAligned(fontTitle, 70, 60, currTheme.textColor, "\uE017", ALIGNED_LEFT); + Gui::drawTextAligned(font24, 70, 23, currTheme.textColor, " About", ALIGNED_LEFT); + + if (updateAvailable) + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0F0 Install update \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + else + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + + Gui::drawTextAligned(fontHuge, 100, 180, Gui::makeColor(0xFB, 0xA6, 0x15, 0xFF), "EdiZon v" VERSION_STRING, ALIGNED_LEFT); + Gui::drawTextAligned(font20, 130, 190, currTheme.separatorColor, "by WerWolv", ALIGNED_LEFT); + + Gui::drawTextAligned(font14, 120, 250, currTheme.textColor, "Special thank to anybody who got involved into this project.", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 120, 270, currTheme.textColor, "Especially to all the config/cheat developers that brought this project to life!", ALIGNED_LEFT); + + Gui::drawTextAligned(font14, 900, 250, Gui::makeColor(0x51, 0x97, 0xF0, 0xFF), "Twitter: https://twitter.com/WerWolv", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 900, 275, Gui::makeColor(0x1A, 0x5E, 0xA7, 0xFF), "PayPal: https://werwolv.net/donate", ALIGNED_LEFT); + + + Gui::drawRectangled(50, 350, Gui::g_framebuffer_width - 100, 250, currTheme.textColor); + Gui::drawRectangled(51, 351, Gui::g_framebuffer_width - 102, updateAvailable ? 190 : 248, currTheme.backgroundColor); + Gui::drawShadow(52, 352, Gui::g_framebuffer_width - 104, 248); + + if (updateAvailable) + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 555, currTheme.backgroundColor, "A update for EdiZon, save editor or cheat is available!", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, 60, 360, currTheme.selectedColor, "EdiZon Update", ALIGNED_LEFT); + + Gui::drawTextAligned(font14, 80, 400, currTheme.textColor, std::string("Latest EdiZon version: " + (remoteVersion == "" ? "..." : remoteVersion)).c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font14, 80, 425, currTheme.textColor, std::string("Latest database commit: [ " + (remoteCommitSha == "" ? "..." : remoteCommitSha) + " ] ").c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font14, 90, 450, currTheme.separatorColor, (remoteCommitMessage == "" ? "..." : remoteCommitMessage.c_str()), ALIGNED_LEFT); + + Gui::endDraw(); +} + +void GuiAbout::onInput(u32 kdown) { + if (kdown & KEY_B) { + if (threadRunning) { + threadWaitForExit(&networkThread); + threadClose(&networkThread); + threadRunning = false; + } + + Gui::g_nextGui = GUI_MAIN; + } + + if (kdown & KEY_MINUS && updateAvailable) { + UpdateManager updateManager; + + (new MessageBox("Updating cheats, configs and EdiZon.\n \nThis may take a while...", MessageBox::NONE))->show(); + requestDraw(); + + Updates updates = updateManager.checkUpdate(); + + switch (updates) { + case NONE: (new MessageBox("Latest cheats and save editors are already installed!", MessageBox::OKAY))->show(); break; + case ERROR: (new MessageBox("An error while downloading the updates has occured!", MessageBox::OKAY))->show(); break; + case EDITOR: (new MessageBox("Updated save editors and cheats to the latest version!", MessageBox::OKAY))->show(); break; + case EDIZON: (new MessageBox("Updated EdiZon, save editors and cheats and \n scripts tothe latest version! \n Please restart EdiZon!", MessageBox::OKAY))->show(); break; + } + + if (updates == EDITOR || updates == EDIZON) { + memcpy(Config::getConfig()->latestCommit, remoteCommitSha.c_str(), remoteCommitSha.size()); + Config::writeConfig(); + } + + updateAvailable = (strcmp(remoteCommitSha.c_str(), Config::getConfig()->latestCommit) != 0 && strcmp(remoteCommitSha.c_str(), "???") != 0); + } +} + +void GuiAbout::onTouch(touchPosition &touch) { + +} + +void GuiAbout::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} + +static size_t writeToStr(const char * contents, size_t size, size_t nmemb, std::string * userp){ + auto totalBytes = (size * nmemb); + + userp->append(contents, totalBytes); + + return totalBytes; +} + +static void getVersionInfoAsync(void* args) { + CURL *curl = curl_easy_init(); + + struct curl_slist * headers = NULL; + headers = curl_slist_append(headers, "Cache-Control: no-cache"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_edizon.php"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteVersion); + + remoteVersion = ""; + if (curl_easy_perform(curl) != CURLE_OK) + remoteVersion = "???"; + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_db_sha.php"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteCommitSha); + + remoteCommitSha = ""; + + if (curl_easy_perform(curl) != CURLE_OK) + remoteCommitSha = "???"; + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/info/latest_db_message.php"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStr); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &remoteCommitMessage); + + remoteCommitMessage = ""; + + if (curl_easy_perform(curl) != CURLE_OK) + remoteCommitMessage = "???"; + + curl_easy_cleanup(curl); + + updateAvailable = (strcmp(remoteCommitSha.c_str(), Config::getConfig()->latestCommit) != 0 && strcmp(remoteCommitSha.c_str(), "???") != 0); +} diff --git a/source/guis/gui_cheats.cpp b/source/guis/gui_cheats.cpp index f2ef121a..eb6795d4 100644 --- a/source/guis/gui_cheats.cpp +++ b/source/guis/gui_cheats.cpp @@ -1,1453 +1,1453 @@ -#include "guis/gui_cheats.hpp" - -#include -#include -#include - -#include -#include - -#include "helpers/util.h" - -#include "edizon_logo_bin.h" - - -static const std::vector dataTypes = { "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "f32", "f64", "ptr" }; -static const std::vector dataTypeSizes = { 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 8 }; -static const std::vector dataTypeMaxValues = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; -static const std::vector dataTypeMinValues = { std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min() }; - -static std::string titleNameStr, tidStr, pidStr, buildIDStr; - -static u32 cheatListOffset = 0; - -static bool _isAddressFrozen(uintptr_t ); -static std::string _getAddressDisplayString(u64 , Debugger *debugger, searchType_t searchType); -static std::string _getValueDisplayString(searchValue_t searchValue, searchType_t searchType); -static void _moveLonelyCheats(u8 *buildID, u64 titleID); -static bool _wrongCheatsPresent(u8 *buildID, u64 titleID); - -GuiCheats::GuiCheats() : Gui() { - - // Check if dmnt:cht is running and we're not on sxos - m_sysmodulePresent = isServiceRunning("dmnt:cht") && !(isServiceRunning("tx") && !isServiceRunning("rnx")); - - m_debugger = new Debugger(); - m_cheats = nullptr; - m_memoryDump = nullptr; - - m_searchValue[0]._u64 = 0; - m_searchValue[1]._u64 = 0; - m_searchType = SEARCH_TYPE_NONE; - m_searchMode = SEARCH_MODE_NONE; - m_searchRegion = SEARCH_REGION_NONE; - - m_cheatCnt = 0; - - if (!m_sysmodulePresent) return; - - dmntchtInitialize(); - dmntchtForceOpenCheatProcess(); - - DmntCheatProcessMetadata metadata; - dmntchtGetCheatProcessMetadata(&metadata); - - m_addressSpaceBaseAddr = metadata.address_space_extents.base; - m_heapBaseAddr = metadata.heap_extents.base; - m_mainBaseAddr = metadata.main_nso_extents.base; - - m_heapSize = metadata.heap_extents.size; - m_mainSize = metadata.main_nso_extents.size; - - memcpy(m_buildID, metadata.main_nso_build_id, 0x20); - - _moveLonelyCheats(m_buildID, m_debugger->getRunningApplicationTID()); - - dmntchtGetCheatCount(&m_cheatCnt); - - if (m_cheatCnt > 0) { - m_cheats = new DmntCheatEntry[m_cheatCnt]; - dmntchtGetCheats(m_cheats, m_cheatCnt, 0, &m_cheatCnt); - } else if (_wrongCheatsPresent(m_buildID, m_debugger->getRunningApplicationTID())) - m_cheatsPresent = true; - - u64 frozenAddressCnt = 0; - dmntchtGetFrozenAddressCount(&frozenAddressCnt); - - if (frozenAddressCnt != 0) { - DmntFrozenAddressEntry frozenAddresses[frozenAddressCnt]; - dmntchtGetFrozenAddresses(frozenAddresses, frozenAddressCnt, 0, nullptr); - - for (u16 i = 0; i < frozenAddressCnt; i++) - m_frozenAddresses.insert({ frozenAddresses[i].address, frozenAddresses[i].value.value }); - - } - - MemoryInfo meminfo = { 0 }; - u64 lastAddr = 0; - - do { - lastAddr = meminfo.addr; - meminfo = m_debugger->queryMemory(meminfo.addr + meminfo.size); - - m_memoryInfo.push_back(meminfo); - } while (lastAddr < meminfo.addr + meminfo.size); - - for (MemoryInfo meminfo : m_memoryInfo) { - if (m_mainBaseAddr == 0x00 && (meminfo.type == MemType_CodeStatic)) - m_mainBaseAddr = meminfo.addr; - - for (u64 addrOffset = meminfo.addr; addrOffset < meminfo.addr + meminfo.size; addrOffset += 0x20000000) { - switch(meminfo.type) { - case MemType_CodeStatic: - case MemType_CodeMutable: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0xFF, 0x00, 0x00, 0xFF); break; - case MemType_SharedMem: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x00, 0xFF, 0x00, 0xFF); break; - case MemType_Heap: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x00, 0x00, 0xFF, 0xFF); break; - case MemType_KernelStack: - case MemType_ThreadLocal: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0xFF, 0xFF, 0x00, 0xFF); break; - case MemType_Unmapped: break; - default: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x80, 0x80, 0x80, 0xFF); break; - } - } - } - - m_memoryDump = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::UNDEFINED, false); - - if (m_debugger->getRunningApplicationPID() == 0 || m_memoryDump->getDumpInfo().heapBaseAddress != m_heapBaseAddr) { - m_memoryDump->clear(); - - remove(EDIZON_DIR "/memdump2.dat"); - remove(EDIZON_DIR "/memdump3.dat"); - - m_searchType = SEARCH_TYPE_NONE; - m_searchRegion = SEARCH_REGION_NONE; - m_searchValue[0]._u64 = 0; - m_searchValue[1]._u64 = 0; - } else { - m_searchType = m_memoryDump->getDumpInfo().searchDataType; - m_searchRegion = m_memoryDump->getDumpInfo().searchRegion; - m_searchValue[0] = m_memoryDump->getDumpInfo().searchValue[0]; - m_searchValue[1] = m_memoryDump->getDumpInfo().searchValue[1]; - } - - m_memoryDump->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); - - std::stringstream ss; - if (m_debugger->getRunningApplicationTID() != 0) { - if (Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName().length() < 24) - ss << Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName(); - else - ss << Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName().substr(0, 21) << "..."; - titleNameStr = ss.str(); - ss.str(""); - } else titleNameStr = "Unknown title name!"; - - ss << "TID: " << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << m_debugger->getRunningApplicationTID(); - tidStr = ss.str(); - ss.str(""); - - ss << "PID: " << std::dec << m_debugger->getRunningApplicationPID(); - pidStr = ss.str(); - ss.str(""); - - ss << "BID: "; - for (u8 i = 0; i < 8; i++) - ss << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)m_buildID[i]; - - buildIDStr = ss.str(); - - if (m_cheatCnt == 0) - m_menuLocation = CANDIDATES; - if (m_memoryDump->size() == 0) - m_menuLocation = CHEATS; - - appletSetMediaPlaybackState(true); -} - -GuiCheats::~GuiCheats() { - - if (m_debugger != nullptr) { - delete m_debugger; - } - - if (m_memoryDump != nullptr) - delete m_memoryDump; - - if (m_cheats != nullptr) - delete[] m_cheats; - - if (m_sysmodulePresent) { - dmntchtExit(); - } - - setLedState(false); - appletSetMediaPlaybackState(false); -} - -void GuiCheats::update() { - Gui::update(); -} - -void GuiCheats::draw() { - static u32 splashCnt = 0; - std::stringstream ss; - - Gui::beginDraw(); - - #if SPLASH_ENABLED - - if (!Gui::g_splashDisplayed) { - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x5D, 0x4F, 0x4E, 0xFF)); - Gui::drawImage(Gui::g_framebuffer_width / 2 - 128, Gui::g_framebuffer_height / 2 - 128, 256, 256, edizon_logo_bin, IMAGE_MODE_BGR24); - - if (splashCnt++ >= 70) - Gui::g_splashDisplayed = true; - - Gui::endDraw(); - return; - } - - #endif - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); - - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); - - if (m_debugger->getRunningApplicationPID() == 0) { - Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "\uE12C", ALIGNED_CENTER); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, currTheme.textColor, "A title needs to be running in the background to use the RAM editor. \n Please launch an application and try again.", ALIGNED_CENTER); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E1 Back", ALIGNED_RIGHT); - Gui::endDraw(); - return; - } else if (!m_sysmodulePresent) { - Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "\uE142", ALIGNED_CENTER); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, currTheme.textColor, "EdiZon depends on Atmosphere's dmnt:cht service which doesn't seem to be \n running on this device. Please install a supported CFW to \n use the cheat engine.", ALIGNED_CENTER); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E1 Back", ALIGNED_RIGHT); - Gui::endDraw(); - return; - } - - if (m_memoryDump->size() == 0) { - if (m_frozenAddresses.size() != 0) - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Frozen es \uE0E3 Search RAM \uE0E1 Back", ALIGNED_RIGHT); - else - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E3 Search RAM \uE0E1 Back", ALIGNED_RIGHT); - } else { - if (m_memoryDump->size() > 0) { - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Reset search \uE0E3 Search again \uE0E2 Freeze value \uE0E0 Edit value \uE0E1 Back", ALIGNED_RIGHT); - } - else - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Reset search \uE0E1 Back", ALIGNED_RIGHT); - } - - Gui::drawRectangle(256, 50, Gui::g_framebuffer_width - 256, 206, currTheme.separatorColor); - - if (m_debugger->getRunningApplicationTID() != 0) - Gui::drawImage(0, 0, 256, 256, Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleIcon(), IMAGE_MODE_RGB24); - else - Gui::drawRectangle(0, 0, 256, 256, Gui::makeColor(0x00, 0x00, 0xFF, 0xFF)); - - Gui::drawRectangle(660, 65, 20, 20, Gui::makeColor(0xFF, 0x00, 0x00, 0xFF)); // Code - Gui::drawRectangle(660, 85, 20, 20, Gui::makeColor(0x00, 0xFF, 0x00, 0xFF)); // Shared Memory - Gui::drawRectangle(660, 105, 20, 20, Gui::makeColor(0x00, 0x00, 0xFF, 0xFF)); // Heap - Gui::drawRectangle(660, 125, 20, 20, Gui::makeColor(0xFF, 0xFF, 0x00, 0xFF)); // Stack - Gui::drawRectangle(660, 145, 20, 20, Gui::makeColor(0x80, 0x80, 0x80, 0xFF)); // Others - - Gui::drawTextAligned(font14, 700, 62, currTheme.textColor, "Code", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 700, 82, currTheme.textColor, "Shared Memory", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 700, 102, currTheme.textColor, "Heap", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 700, 122, currTheme.textColor, "Stack", ALIGNED_LEFT); - Gui::drawTextAligned(font14, 700, 142, currTheme.textColor, "Others", ALIGNED_LEFT); - - - ss.str(""); - ss << "BASE : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_addressSpaceBaseAddr; - Gui::drawTextAligned(font14, 900, 75, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - ss.str(""); - ss << "HEAP : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_heapBaseAddr; - Gui::drawTextAligned(font14, 900, 105, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - ss.str(""); - ss << "MAIN : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_mainBaseAddr; - Gui::drawTextAligned(font14, 900, 135, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - - - Gui::drawRectangle(256, 50, 394, 137, COLOR_WHITE); - - Gui::drawTextAligned(font20, 280, 70, COLOR_BLACK, titleNameStr.c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font14, 290, 110, COLOR_BLACK, tidStr.c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font14, 290, 130, COLOR_BLACK, pidStr.c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font14, 290, 150, COLOR_BLACK, buildIDStr.c_str(), ALIGNED_LEFT); - - if (Account::g_activeUser != 0) { - ss.str(""); - ss << Account::g_accounts[Account::g_activeUser]->getUserName() << " [ " << std::hex << (u64)(Account::g_activeUser >> 64) << " " << (u64)(Account::g_activeUser & 0xFFFFFFFFFFFFFFFFULL) << " ]"; - Gui::drawTextAligned(font20, 768, 205, currTheme.textColor, ss.str().c_str(), ALIGNED_CENTER); - } - - if (m_cheatCnt > 0) { - Gui::drawRectangle(50, 256, 650, 46 + std::min(static_cast(m_cheatCnt), 8U) * 40, currTheme.textColor); - Gui::drawTextAligned(font14, 375, 262, currTheme.backgroundColor, "Cheats", ALIGNED_CENTER); - Gui::drawShadow(50, 256, 650, 46 + std::min(static_cast(m_cheatCnt), 8U) * 40); - - for (u8 line = cheatListOffset; line < 8 + cheatListOffset; line++) { - if (line >= m_cheatCnt) break; - - ss.str(""); - ss << "\uE070 " << m_cheats[line].definition.readable_name; - - Gui::drawRectangle(52, 300 + (line - cheatListOffset) * 40, 646, 40, (m_selectedEntry == line && m_menuLocation == CHEATS) ? currTheme.highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); - Gui::drawTextAligned(font14, 70, 305 + (line - cheatListOffset) * 40, (m_selectedEntry == line && m_menuLocation == CHEATS) ? COLOR_BLACK : currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - - if (!m_cheats[line].enabled) { - color_t highlightColor = currTheme.highlightColor; - highlightColor.a = 0xFF; - - Gui::drawRectangled(74, 313 + (line - cheatListOffset) * 40, 10, 10, (m_selectedEntry == line && m_menuLocation == CHEATS) ? highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); - } - } - } else if (m_cheatsPresent && m_memoryDump->size() == 0) - Gui::drawTextAligned(font24, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 + 50, currTheme.textColor, "Cheats for this game present but title version or region doesn't match!", ALIGNED_CENTER); - - - if (m_memoryDump->getDumpInfo().dumpType == DumpType::DATA) { - if (m_memoryDump->size() > 0) { - Gui::drawRectangle(Gui::g_framebuffer_width - 552, 256, 500, 366, currTheme.textColor); - Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 302, 262, currTheme.backgroundColor, "Found candidates", ALIGNED_CENTER); - Gui::drawShadow(Gui::g_framebuffer_width - 552, 256, 500, 366 * 40); - Gui::drawRectangle(Gui::g_framebuffer_width - 550, 300, 496, 320, currTheme.separatorColor); - - - ss.str(""); - ss << (static_cast(m_memoryDump->size()) / (0x100000)) << "MB dumped"; - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 302, 450, currTheme.textColor, ss.str().c_str(), ALIGNED_CENTER); - } - } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { - if (m_memoryDump->size() > 0) { - Gui::drawRectangle(Gui::g_framebuffer_width - 552, 256, 500, 46 + std::min(static_cast(m_memoryDump->size() / sizeof(u64)), 8U) * 40, currTheme.textColor); - Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 302, 262, currTheme.backgroundColor, "Found candidates", ALIGNED_CENTER); - Gui::drawShadow(Gui::g_framebuffer_width - 552, 256, 500, 46 + std::min(static_cast(m_memoryDump->size() / sizeof(u64)), 8U) * 40); - } - - for (u8 line = 0; line < 8; line++) { - if (line >= (m_memoryDump->size() / sizeof(u64))) break; - - ss.str(""); - - if (line < 7 && (m_memoryDump->size() / sizeof(u64)) != 8) { - u64 address = 0; - m_memoryDump->getData(line * sizeof(u64), &address, sizeof(u64)); - - if (address >= m_memoryDump->getDumpInfo().heapBaseAddress && address < (m_memoryDump->getDumpInfo().heapBaseAddress + m_memoryDump->getDumpInfo().heapSize)) - ss << "[ HEAP + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().heapBaseAddress) << " ]"; - else if (address >= m_memoryDump->getDumpInfo().mainBaseAddress && address < (m_memoryDump->getDumpInfo().mainBaseAddress + m_memoryDump->getDumpInfo().mainSize)) - ss << "[ MAIN + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().mainBaseAddress) << " ]"; - else - ss << "[ BASE + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().addrSpaceBaseAddress) << " ]"; - - ss << " ( " << _getAddressDisplayString(address, m_debugger, (searchType_t)m_searchType) << " )"; - - if (m_frozenAddresses.find(address) != m_frozenAddresses.end()) - ss << " \uE130"; - } - else - ss << "And " << std::dec << ((m_memoryDump->size() / sizeof(u64)) - 8) << " others..."; - - Gui::drawRectangle(Gui::g_framebuffer_width - 550, 300 + line * 40, 496, 40, (m_selectedEntry == line && m_menuLocation == CANDIDATES) ? currTheme.highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); - Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 530, 305 + line * 40, (m_selectedEntry == line && m_menuLocation == CANDIDATES) ? COLOR_BLACK : currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - } - } - - Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 256); - Gui::drawShadow(256, 50, Gui::g_framebuffer_width, 136); - - for (u16 x = 0; x < 1024; x++) - Gui::drawRectangle(256 + x, 0, 2, 50, m_memory[x]); - - drawSearchRAMMenu(); - - Gui::endDraw(); -} - -void GuiCheats::drawSearchRAMMenu() { - static u32 cursorBlinkCnt = 0; - u32 strWidth = 0; - std::stringstream ss; - - if (m_searchMenuLocation == SEARCH_NONE) return; - - Gui::drawRectangled(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x00, 0x00, 0x00, 0xA0)); - - Gui::drawRectangle(50, 50, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.backgroundColor); - Gui::drawRectangle(100, 135, Gui::g_framebuffer_width - 200, 1, currTheme.textColor); - Gui::drawText(font24, 120, 70, currTheme.textColor, "\uE132 Search Memory"); - - Gui::drawTextAligned(font20, 100, 160, currTheme.textColor, "\uE149 \uE0A4", ALIGNED_LEFT); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, 160, currTheme.textColor, "\uE0A5 \uE14A", ALIGNED_RIGHT); - - Gui::drawTextAligned(font20, 260, 160, m_searchMenuLocation == SEARCH_TYPE ? currTheme.selectedColor : currTheme.textColor, "TYPE", ALIGNED_CENTER); - Gui::drawTextAligned(font20, 510, 160, m_searchMenuLocation == SEARCH_MODE ? currTheme.selectedColor : currTheme.textColor, "MODE", ALIGNED_CENTER); - Gui::drawTextAligned(font20, 760, 160, m_searchMenuLocation == SEARCH_REGION ? currTheme.selectedColor : currTheme.textColor, "REGION", ALIGNED_CENTER); - Gui::drawTextAligned(font20, 1010, 160, m_searchMenuLocation == SEARCH_VALUE ? currTheme.selectedColor : currTheme.textColor, "VALUE", ALIGNED_CENTER); - - static const char* const typeNames[] = { "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "flt", "dbl", "void*" }; - static const char* const modeNames[] = { "==", "!=", ">", ">=", "<", "<=", "A..B", "SAME", "DIFF", "+ +", "- -" }; - static const char* const regionNames[] = { "HEAP", "MAIN", "HEAP + MAIN", "RAM" }; - - switch (m_searchMenuLocation) { - case SEARCH_TYPE: - for (u8 i = 0; i < 11; i++) { - if (m_selectedEntry == i) - Gui::drawRectangled(356 + (i / 2) * 100, 220 + (i % 2) * 100, 90, 90, m_searchType == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); - - Gui::drawRectangled(361 + (i / 2) * 100, 225 + (i % 2) * 100, 80, 80, currTheme.separatorColor); - Gui::drawTextAligned(font20, 400 + (i / 2) * 100, 250 + (i % 2) * 100, currTheme.textColor, typeNames[i], ALIGNED_CENTER); - } - - Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the data type of the value you’re searching here. The prefix [u] means unsigned (positive integers), [s] means \n" - "signed (positive and negative integers), [flt] is for floating point numbers (rational numbers), [dbl] is for double (bigger \n" - "rational numbers) and [void*] stands for pointer (link to another memory ) which is useful for creating cheats. The \n" - "number that follows is the number of bits used in memory which determines the maximum value. Choose the data type that \n" - "best fits for the type of data you’re looking for.", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - - break; - case SEARCH_MODE: - for (u8 i = 0; i < 11; i++) { - if (m_selectedEntry == i) - Gui::drawRectangled(356 + (i / 2) * 100, 220 + (i % 2) * 100, 90, 90, m_searchMode == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); - - Gui::drawRectangled(361 + (i / 2) * 100, 225 + (i % 2) * 100, 80, 80, currTheme.separatorColor); - Gui::drawTextAligned(font20, 400 + (i / 2) * 100, 250 + (i % 2) * 100, currTheme.textColor, modeNames[i], ALIGNED_CENTER); - } - - Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the mode you want to use for finding values. With these modes EdiZon will search for values that are equal to [==], \n" - "not equal to [!=], greater than [>], greater than or equal to [>=], less than [<], or less than or equal to [<=] the value \n" - "that you input. [A : B] allows you to set a (min : max) range of values, SAME and DIFF search allows you to find values that \n" - "stayed the same or changed since the last search, [+ +] and [- -] checks for values that increased or decreased since the \n" - "previous search.", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - break; - case SEARCH_REGION: - for (u8 i = 0; i < 4; i++) { - if (m_selectedEntry == i) - Gui::drawRectangled((Gui::g_framebuffer_width / 2) - 155, 215 + i * 70, 310, 70, m_searchRegion == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); - - Gui::drawRectangled((Gui::g_framebuffer_width / 2) - 150, 220 + i * 70, 300, 60, currTheme.separatorColor); - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 235 + i * 70, currTheme.textColor, regionNames[i], ALIGNED_CENTER); - } - - - Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the memory region you want to search in. HEAP contains dynamically allocated values and will be where the majority of \n" - "values worth changing will be found. MAIN contains global variables and instructions for game operation. You may find some \n" - "values here but it’s mainly for finding pointers to HEAP values or changing game code. RAM will search the entirety of the Games \n" - "used memory including memory shared memory and resources. Should only be used as a final resort as this will be extremely slow. \n", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - break; - case SEARCH_VALUE: - Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the value you want to search for. The value(s) you enter here will depend on what options you've chosen in the \n" - "first three sections. Either it's the exact integer you want to search for, a floating point number or even two values that \n" - "will be used as range.", ALIGNED_CENTER); - - //Gui::drawRectangle(300, 250, Gui::g_framebuffer_width - 600, 80, currTheme.separatorColor); - Gui::drawRectangle(300, 327, Gui::g_framebuffer_width - 600, 3, currTheme.textColor); - if (m_searchValueFormat == FORMAT_DEC) - ss << _getValueDisplayString(m_searchValue[0], m_searchType); - else if (m_searchValueFormat == FORMAT_HEX) - ss << "0x" << std::uppercase << std::hex << m_searchValue[0]._u64; - - Gui::getTextDimensions(font20, ss.str().c_str(), &strWidth, nullptr); - Gui::drawTextAligned(font20, 310, 285, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); - - if (cursorBlinkCnt++ % 20 > 10 && m_selectedEntry == 0) - Gui::drawRectangled(312 + strWidth, 285, 3, 35, currTheme.highlightColor); - - if (m_searchValueFormat == FORMAT_DEC) - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E2 Hexadecimal view \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - else if (m_searchValueFormat == FORMAT_HEX) - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E2 Decimal view \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); - - if (m_selectedEntry == 1) - Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 155, 345, 310, 90, currTheme.highlightColor); - - if (m_searchType != SEARCH_TYPE_NONE && m_searchMode != SEARCH_MODE_NONE && m_searchRegion != SEARCH_REGION_NONE) { - Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 150, 350, 300, 80, currTheme.selectedColor); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 375, currTheme.backgroundColor, "Search Now!", ALIGNED_CENTER); - } - else { - Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 150, 350, 300, 80, currTheme.selectedButtonColor); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 375, currTheme.separatorColor, "Search Now!", ALIGNED_CENTER); - } - - - break; - case SEARCH_NONE: break; - } -} - -void GuiCheats::onInput(u32 kdown) { - if (kdown & KEY_B) { - - if (m_searchMenuLocation == SEARCH_NONE) { - Gui::g_nextGui = GUI_MAIN; - return; - } - else if (m_searchMenuLocation == SEARCH_TYPE) { - if (m_searchType != SEARCH_TYPE_NONE && m_memoryDump->size() == 0) - m_searchType = SEARCH_TYPE_NONE; - else - m_searchMenuLocation = SEARCH_NONE; - } - else if (m_searchMenuLocation == SEARCH_MODE) { - if (m_searchMode != SEARCH_MODE_NONE) - m_searchMode = SEARCH_MODE_NONE; - else - m_searchMenuLocation = SEARCH_NONE; - } - else if (m_searchMenuLocation == SEARCH_REGION) { - if (m_searchRegion != SEARCH_REGION_NONE && m_memoryDump->size() == 0) - m_searchRegion = SEARCH_REGION_NONE; - else - m_searchMenuLocation = SEARCH_NONE; - } - else if (m_searchMenuLocation == SEARCH_VALUE) - m_searchMenuLocation = SEARCH_NONE; - } - - if (m_debugger->getRunningApplicationPID() == 0) - return; - - if (m_searchMenuLocation == SEARCH_NONE) { - if (kdown & KEY_UP) { - if (m_selectedEntry > 0) - m_selectedEntry--; - - if (m_menuLocation == CHEATS) - if (m_selectedEntry == cheatListOffset && cheatListOffset > 0) - cheatListOffset--; - } - - if (kdown & KEY_DOWN) { - if (m_menuLocation == CANDIDATES) { - if (m_selectedEntry < 7 && m_selectedEntry < ((m_memoryDump->size() / sizeof(u64)) - 1)) - m_selectedEntry++; - } else { - if (m_selectedEntry < (m_cheatCnt - 1)) - m_selectedEntry++; - - if (m_selectedEntry == (cheatListOffset + 7) && cheatListOffset < (m_cheatCnt - 8)) - cheatListOffset++; - } - } - - if (m_memoryDump->size() > 0) { - if (kdown & KEY_LEFT) - if (m_cheatCnt > 0) { - m_menuLocation = CHEATS; - m_selectedEntry = 0; - cheatListOffset = 0; - } - - if (kdown & KEY_RIGHT) { - m_menuLocation = CANDIDATES; - m_selectedEntry = 0; - cheatListOffset = 0; - } - } - - if (m_menuLocation == CANDIDATES) { /* Candidates menu */ - if (m_memoryDump->size() > 0) { - if (kdown & KEY_X && m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { - u64 address = 0; - m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); - if (!_isAddressFrozen(address)) { - u64 outValue; - - if (R_SUCCEEDED(dmntchtEnableFrozenAddress(address, dataTypeSizes[m_searchType], &outValue))) { - (new Snackbar("Froze variable!"))->show(); - m_frozenAddresses.insert({ address, outValue }); - } - else - (new Snackbar("Failed to freeze variable!"))->show(); - } - else { - if (R_SUCCEEDED(dmntchtDisableFrozenAddress(address))) { - (new Snackbar("Unfroze variable!"))->show(); - m_frozenAddresses.erase(address); - } - else - (new Snackbar("Failed to unfreeze variable!"))->show(); - } - } - - if (kdown & KEY_A && m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { - u64 address = 0; - m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); - - if (m_selectedEntry < 7) { - char input[16]; - char initialString[21]; - - strcpy(initialString, _getAddressDisplayString(address, m_debugger, m_searchType).c_str()); - - if (Gui::requestKeyboardInput("Enter value", "Enter a value that should get written at this .", initialString, SwkbdType::SwkbdType_NumPad, input, 15)) { - m_debugger->pokeMemory(dataTypeSizes[m_searchType], address, atol(input)); - } - } - else if ((m_memoryDump->size() / sizeof(u64)) < 25) { - std::vector options; - options.clear(); - - std::stringstream ss; - for (u32 i = 7; i < (m_memoryDump->size() / sizeof(u64)); i++) { //TODO: i? - m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); - ss.str(""); - ss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << address; - - ss << " (" << _getAddressDisplayString(address, m_debugger, m_searchType); - - options.push_back(ss.str()); - printf("%s\n", ss.str().c_str()); - } - - (new ListSelector("Edit value at ", "\uE0E0 Edit value \uE0E1 Back", options))->setInputAction([&](u32 k, u16 selectedItem) { - if (k & KEY_A) { - char input[16]; - char initialString[21]; - u64 selectedAddress; - - m_memoryDump->getData((selectedItem + 7) * sizeof(u64), &selectedAddress, sizeof(u64)); - - strcpy(initialString, _getAddressDisplayString(selectedAddress, m_debugger, m_searchType).c_str()); - - if (Gui::requestKeyboardInput("Enter value", "Enter a value for which the game's memory should be searched.", initialString, SwkbdType::SwkbdType_NumPad, input, 15)) { - u64 value = atol(input); - if (value > dataTypeMaxValues[m_searchType] || value < dataTypeMinValues[m_searchType]) { - (new Snackbar("Entered value isn't inside the range of this data type. Please enter a different value."))->show(); - return; - } - - m_memoryDump->getData((m_selectedEntry) * sizeof(u64), &selectedAddress, sizeof(u64)); - m_debugger->pokeMemory(dataTypeSizes[m_searchType], selectedAddress, value); - } - } - })->show(); - } else (new Snackbar("Too many addresses! Narrow down the selection before editing."))->show(); - } - } - } else { /* Cheats menu */ - if (kdown & KEY_A) { - if (m_cheatCnt == 0) return; - - dmntchtToggleCheat(m_cheats[m_selectedEntry].cheat_id); - u64 cheatCnt = 0; - - dmntchtGetCheatCount(&cheatCnt); - if (cheatCnt > 0) { - delete[] m_cheats; - m_cheats = new DmntCheatEntry[cheatCnt]; - dmntchtGetCheats(m_cheats, cheatCnt, 0, &m_cheatCnt); - } - } - } - - if (kdown & KEY_MINUS) { - if (m_memoryDump->size() == 0) { - std::vector options; - - if (m_frozenAddresses.size() == 0) - return; - - std::stringstream ss; - for (auto [addr, value] : m_frozenAddresses) { - ss << "[ BASE + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (addr - m_addressSpaceBaseAddr) << " ] "; - ss << "( " << std::dec << value << " )"; - options.push_back(ss.str()); - ss.str(""); - } - - (new ListSelector("Frozen Addresses", "\uE0E0 Unfreeze \uE0E1 Back", options))->setInputAction([&](u32 k, u16 selectedItem) { - if (k & KEY_A) { - auto itr = m_frozenAddresses.begin(); - std::advance(itr, selectedItem); - - dmntchtDisableFrozenAddress(itr->first); - m_frozenAddresses.erase(itr->first); - } - })->show(); - } else { - m_memoryDump->clear(); - remove(EDIZON_DIR "/memdump1.dat"); - remove(EDIZON_DIR "/memdump2.dat"); - remove(EDIZON_DIR "/memdump3.dat"); - - m_searchType = SEARCH_TYPE_NONE; - m_searchMode = SEARCH_MODE_NONE; - m_searchRegion = SEARCH_REGION_NONE; - m_searchValue[0]._u64 = 0; - m_searchValue[1]._u64 = 0; - - m_menuLocation = CHEATS; - } - } - - if (kdown & KEY_Y) { - if (m_searchMenuLocation == SEARCH_NONE) { - m_searchMenuLocation = SEARCH_TYPE; - m_selectedEntry = m_searchType == SEARCH_TYPE_NONE ? 0 : m_searchType; - cheatListOffset = 0; - } - } - } - else { - if ((m_searchMenuLocation == SEARCH_TYPE && m_searchType == SEARCH_TYPE_NONE) || - (m_searchMenuLocation == SEARCH_MODE && m_searchMode == SEARCH_MODE_NONE) || - (m_searchMenuLocation == SEARCH_REGION && m_searchRegion == SEARCH_REGION_NONE) || - (m_searchMenuLocation == SEARCH_VALUE)) { - if (kdown & KEY_UP) { - switch (m_searchMenuLocation) { - case SEARCH_TYPE: [[fallthrough]] - case SEARCH_MODE: - if (m_selectedEntry % 2 == 1) - m_selectedEntry--; - break; - case SEARCH_REGION: - if (m_selectedEntry > 0) - m_selectedEntry--; - break; - case SEARCH_VALUE: - m_selectedEntry = 0; - break; - case SEARCH_NONE: break; - } - } - - if (kdown & KEY_DOWN) { - switch (m_searchMenuLocation) { - case SEARCH_TYPE: [[fallthrough]] - case SEARCH_MODE: - if ((m_selectedEntry + 1) < 10 && m_selectedEntry % 2 == 0) - m_selectedEntry++; - break; - case SEARCH_REGION: - if (m_selectedEntry < 3) - m_selectedEntry++; - break; - case SEARCH_VALUE: - if (m_searchType != SEARCH_TYPE_NONE && m_searchMode != SEARCH_MODE_NONE && m_searchRegion != SEARCH_REGION_NONE) - m_selectedEntry = 1; - break; - case SEARCH_NONE: break; - } - } - - if (kdown & KEY_LEFT) { - switch (m_searchMenuLocation) { - case SEARCH_TYPE: [[fallthrough]] - case SEARCH_MODE: - if (m_selectedEntry >= 2) - m_selectedEntry -= 2; - break; - case SEARCH_REGION: - break; - case SEARCH_VALUE: - break; - case SEARCH_NONE: break; - } - } - - if (kdown & KEY_RIGHT) { - switch (m_searchMenuLocation) { - case SEARCH_TYPE: [[fallthrough]] - case SEARCH_MODE: - if (m_selectedEntry <= 8) - m_selectedEntry += 2; - break; - case SEARCH_REGION: - break; - case SEARCH_VALUE: - break; - case SEARCH_NONE: break; - } - } - - if (kdown & KEY_A) { - if (m_searchMenuLocation == SEARCH_TYPE) - m_searchType = static_cast(m_selectedEntry); - else if (m_searchMenuLocation == SEARCH_REGION) - m_searchRegion = static_cast(m_selectedEntry); - else if (m_searchMenuLocation == SEARCH_MODE) - m_searchMode = static_cast(m_selectedEntry); - else if (m_searchMenuLocation == SEARCH_VALUE) { - if (m_selectedEntry == 0) { - char str[0x21]; - Gui::requestKeyboardInput("Enter the value you want to search for", "Based on your previously chosen options, EdiZon will expect different input here.", "", m_searchValueFormat == FORMAT_DEC ? SwkbdType_NumPad : SwkbdType_QWERTY, str, 0x20); - - if (std::string(str) == "") return; - - if (m_searchValueFormat == FORMAT_HEX) { - m_searchValue[0]._u64 = static_cast(std::stoul(str, nullptr, 16)); - } else { - switch(m_searchType) { - case SEARCH_TYPE_UNSIGNED_8BIT: - m_searchValue[0]._u8 = static_cast(std::stoul(str, nullptr, 0)); - break; - case SEARCH_TYPE_UNSIGNED_16BIT: - m_searchValue[0]._u16 = static_cast(std::stoul(str, nullptr, 0)); - break; - case SEARCH_TYPE_UNSIGNED_32BIT: - m_searchValue[0]._u32 = static_cast(std::stoul(str, nullptr, 0)); - break; - case SEARCH_TYPE_UNSIGNED_64BIT: - m_searchValue[0]._u64 = static_cast(std::stoul(str, nullptr, 0)); - break; - case SEARCH_TYPE_SIGNED_8BIT: - m_searchValue[0]._s8 = static_cast(std::stol(str, nullptr, 0)); - break; - case SEARCH_TYPE_SIGNED_16BIT: - m_searchValue[0]._s16 = static_cast(std::stol(str, nullptr, 0)); - break; - case SEARCH_TYPE_SIGNED_32BIT: - m_searchValue[0]._s32 = static_cast(std::stol(str, nullptr, 0)); - break; - case SEARCH_TYPE_SIGNED_64BIT: - m_searchValue[0]._s64 = static_cast(std::stol(str, nullptr, 0)); - break; - case SEARCH_TYPE_FLOAT_32BIT: - m_searchValue[0]._f32 = static_cast(std::stof(str)); - break; - case SEARCH_TYPE_FLOAT_64BIT: - m_searchValue[0]._f64 = static_cast(std::stod(str)); - break; - case SEARCH_TYPE_POINTER: - m_searchValue[0]._u64 = static_cast(std::stol(str)); - break; - case SEARCH_TYPE_NONE: break; - } - } - } else if (m_selectedEntry == 1) { - (new MessageBox("Traversing title memory.\n \nThis may take a while...", MessageBox::NONE))->show(); - requestDraw(); - - overclockSystem(true); - - if (m_searchMode == SEARCH_MODE_SAME || m_searchMode == SEARCH_MODE_DIFF || m_searchMode == SEARCH_MODE_INC || m_searchMode == SEARCH_MODE_DEC) { - if (m_memoryDump->size() == 0) { - delete m_memoryDump; - GuiCheats::searchMemoryValuesPrimary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); - } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::DATA) { - GuiCheats::searchMemoryValuesSecondary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); - delete m_memoryDump; - - remove(EDIZON_DIR "/memdump1.dat"); - rename(EDIZON_DIR "/memdump3.dat", EDIZON_DIR "/memdump1.dat"); - - m_memoryDump = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::ADDR, false); - } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { - GuiCheats::searchMemoryValuesTertiary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); - } - } else { - if (m_memoryDump->size() == 0) { - delete m_memoryDump; - GuiCheats::searchMemoryAddressesPrimary(m_debugger, m_searchValue[0], m_searchValue[1], m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); - } else { - GuiCheats::searchMemoryAddressesSecondary(m_debugger, m_searchValue[0], m_searchValue[1], m_searchType, m_searchMode, &m_memoryDump); - } - } - - overclockSystem(false); - - Gui::g_currMessageBox->hide(); - - m_searchMenuLocation = SEARCH_NONE; - m_searchMode = SEARCH_MODE_NONE; - } - } - } - } - - if (kdown & KEY_X) { - if (m_searchMenuLocation == SEARCH_VALUE) { - if (m_searchValueFormat == FORMAT_DEC) - m_searchValueFormat = FORMAT_HEX; - else - m_searchValueFormat = FORMAT_DEC; - } - } - - if (kdown & KEY_L) { - if (m_searchMenuLocation == SEARCH_VALUE) { - m_searchMenuLocation = SEARCH_REGION; - m_selectedEntry = m_searchRegion == SEARCH_REGION_NONE ? 0 : static_cast(m_searchRegion); - } - else if (m_searchMenuLocation == SEARCH_REGION) { - m_searchMenuLocation = SEARCH_MODE; - m_selectedEntry = m_searchMode == SEARCH_MODE_NONE ? 0 : static_cast(m_searchMode); - } - else if (m_searchMenuLocation == SEARCH_MODE) { - m_searchMenuLocation = SEARCH_TYPE; - m_selectedEntry = m_searchType == SEARCH_TYPE_NONE ? 0 : static_cast(m_searchType); - } - } - - if (kdown & KEY_R) { - if (m_searchMenuLocation == SEARCH_TYPE) { - m_searchMenuLocation = SEARCH_MODE; - m_selectedEntry = m_searchMode == SEARCH_MODE_NONE ? 0 : static_cast(m_searchMode); - } - else if (m_searchMenuLocation == SEARCH_MODE) { - m_searchMenuLocation = SEARCH_REGION; - m_selectedEntry = m_searchRegion == SEARCH_REGION_NONE ? 0 : static_cast(m_searchRegion); - } - else if (m_searchMenuLocation == SEARCH_REGION) { - m_searchMenuLocation = SEARCH_VALUE; - m_selectedEntry = 0; - } - } - - } -} - -void GuiCheats::onTouch(touchPosition &touch) { - -} - -void GuiCheats::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} - -static bool _isAddressFrozen(uintptr_t address) { - DmntFrozenAddressEntry *es; - u64 Cnt = 0; - bool frozen = false; - - dmntchtGetFrozenAddressCount(&Cnt); - - if (Cnt != 0) { - es = new DmntFrozenAddressEntry[Cnt]; - dmntchtGetFrozenAddresses(es, Cnt, 0, nullptr); - - for (u64 i = 0; i < Cnt; i++) { - if (es[i].address == address) { - frozen = true; - break; - } - } - } - - return frozen; -} - -static std::string _getAddressDisplayString(u64 address, Debugger *debugger, searchType_t searchType) { - std::stringstream ss; - - searchValue_t searchValue; - searchValue._u64 = debugger->peekMemory(address); - - switch(searchType) { - case SEARCH_TYPE_UNSIGNED_8BIT: - ss << std::dec << static_cast(searchValue._u8); - break; - case SEARCH_TYPE_UNSIGNED_16BIT: - ss << std::dec << static_cast(searchValue._u16); - break; - case SEARCH_TYPE_UNSIGNED_32BIT: - ss << std::dec << static_cast(searchValue._u32); - break; - case SEARCH_TYPE_UNSIGNED_64BIT: - ss << std::dec << static_cast(searchValue._u64); - break; - case SEARCH_TYPE_SIGNED_8BIT: - ss << std::dec << static_cast(searchValue._s8); - break; - case SEARCH_TYPE_SIGNED_16BIT: - ss << std::dec << static_cast(searchValue._s16); - break; - case SEARCH_TYPE_SIGNED_32BIT: - ss << std::dec << static_cast(searchValue._s32); - break; - case SEARCH_TYPE_SIGNED_64BIT: - ss << std::dec << static_cast(searchValue._s64); - break; - case SEARCH_TYPE_FLOAT_32BIT: - ss << std::dec << searchValue._f32; - break; - case SEARCH_TYPE_FLOAT_64BIT: - ss << std::dec << searchValue._f64; - break; - case SEARCH_TYPE_POINTER: - ss << std::dec << searchValue._u64; - break; - case SEARCH_TYPE_NONE: break; - } - - return ss.str(); -} - -static std::string _getValueDisplayString(searchValue_t searchValue, searchType_t searchType) { - std::stringstream ss; - - switch(searchType) { - case SEARCH_TYPE_UNSIGNED_8BIT: - ss << std::dec << static_cast(searchValue._u8); - break; - case SEARCH_TYPE_UNSIGNED_16BIT: - ss << std::dec << static_cast(searchValue._u16); - break; - case SEARCH_TYPE_UNSIGNED_32BIT: - ss << std::dec << static_cast(searchValue._u32); - break; - case SEARCH_TYPE_UNSIGNED_64BIT: - ss << std::dec << static_cast(searchValue._u64); - break; - case SEARCH_TYPE_SIGNED_8BIT: - ss << std::dec << static_cast(searchValue._s8); - break; - case SEARCH_TYPE_SIGNED_16BIT: - ss << std::dec << static_cast(searchValue._s16); - break; - case SEARCH_TYPE_SIGNED_32BIT: - ss << std::dec << static_cast(searchValue._s32); - break; - case SEARCH_TYPE_SIGNED_64BIT: - ss << std::dec << static_cast(searchValue._s64); - break; - case SEARCH_TYPE_FLOAT_32BIT: - ss.precision(15); - ss << std::dec << searchValue._f32; - break; - case SEARCH_TYPE_FLOAT_64BIT: - ss.precision(15); - ss << std::dec << searchValue._f64; - break; - case SEARCH_TYPE_POINTER: - ss << std::dec << searchValue._u64; - break; - case SEARCH_TYPE_NONE: break; - } - - return ss.str(); -} - -void GuiCheats::searchMemoryAddressesPrimary(Debugger *debugger, searchValue_t searchValue1, searchValue_t searchValue2, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { - (*displayDump) = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::ADDR, true); - (*displayDump)->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); - (*displayDump)->setSearchParams(searchType, searchMode, searchRegion, searchValue1, searchValue2); - - bool ledOn = false; - - for (MemoryInfo meminfo : memInfos) { - if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) - continue; - else if (searchRegion == SEARCH_REGION_MAIN && - (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && - (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) - continue; - - setLedState(ledOn); - ledOn = !ledOn; - - u64 offset = 0; - u64 bufferSize = 0x10000; - u8 *buffer = new u8[bufferSize]; - while (offset < meminfo.size) { - - if (meminfo.size - offset < bufferSize) - bufferSize = meminfo.size - offset; - - debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); - - searchValue_t realValue = { 0 }; - for (u32 i = 0; i < bufferSize; i += dataTypeSizes[searchType]) { - u64 address = meminfo.addr + offset + i; - memset(&realValue, 0, 8); - memcpy(&realValue, buffer + i, dataTypeSizes[searchType]); - - switch(searchMode) { - case SEARCH_MODE_EQ: - if (realValue._s64 == searchValue1._s64) { - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - break; - case SEARCH_MODE_NEQ: - if (realValue._s64 != searchValue1._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_GT: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (realValue._s64 > searchValue1._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } else { - if (realValue._u64 > searchValue1._u64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - break; - case SEARCH_MODE_GTE: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (realValue._s64 >= searchValue1._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } else { - if (realValue._u64 >= searchValue1._u64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - break; - case SEARCH_MODE_LT: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (realValue._s64 < searchValue1._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } else { - if (realValue._u64 < searchValue1._u64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - break; - case SEARCH_MODE_LTE: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (realValue._s64 <= searchValue1._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } else { - if (realValue._u64 <= searchValue1._u64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - break; - case SEARCH_MODE_RANGE: - if (realValue._s64 >= searchValue1._s64 && realValue._s64 <= searchValue2._s64) - (*displayDump)->addData((u8*)&address, sizeof(u64)); - break; - } - } - - offset += bufferSize; - } - - delete[] buffer; - } - - setLedState(false); - - (*displayDump)->flushBuffer(); -} - -void GuiCheats::searchMemoryAddressesSecondary(Debugger *debugger, searchValue_t searchValue1, searchValue_t searchValue2, searchType_t searchType, searchMode_t searchMode, MemoryDump **displayDump) { - MemoryDump *newDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::ADDR, true); - bool ledOn = false; - - for (size_t i = 0; i < ((*displayDump)->size() / sizeof(u64)); i++) { - searchValue_t value = { 0 }; - u64 address = 0; - (*displayDump)->getData(i * sizeof(u64), &address, sizeof(u64)); - - debugger->readMemory(&value, dataTypeSizes[searchType], address); - - if (i % 50 == 0) { - setLedState(ledOn); - ledOn = !ledOn; - } - - switch(searchMode) { - case SEARCH_MODE_EQ: - if (value._s64 == searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_NEQ: - if (value._s64 != searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_GT: - if (value._s64 > searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_GTE: - if (value._s64 >= searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_LT: - if (value._s64 < searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_LTE: - if (value._s64 <= searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_RANGE: - if (value._s64 >= searchValue1._s64 && value._s64 <= searchValue2._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_SAME: - if (value._s64 == searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_DIFF: - if (value._s64 != searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_INC: - if (value._s64 > searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_DEC: - if (value._s64 < searchValue1._s64) - newDump->addData((u8*)&address, sizeof(u64)); - break; - case SEARCH_MODE_NONE: break; - } - } - - if (newDump->size() > 0) { - (*displayDump)->clear(); - (*displayDump)->setSearchParams(searchType, searchMode, (*displayDump)->getDumpInfo().searchRegion, searchValue1, searchValue2); - (*displayDump)->setDumpType(DumpType::ADDR); - - for (size_t i = 0; i < (newDump->size() / sizeof(u64)); i++) { - u64 address = 0; - - newDump->getData(i * sizeof(u64), &address, sizeof(u64)); - (*displayDump)->addData((u8*)&address, sizeof(u64)); - } - - (*displayDump)->flushBuffer(); - } else { - (new Snackbar("None of values changed to the entered one!"))->show(); - } - - setLedState(false); - - delete newDump; - - remove(EDIZON_DIR "/memdump2.dat"); -} - -void GuiCheats::searchMemoryValuesPrimary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { - bool ledOn = false; - - searchValue_t zeroValue; - zeroValue._u64 = 0; - - (*displayDump) = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::DATA, true); - (*displayDump)->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); - (*displayDump)->setSearchParams(searchType, searchMode, searchRegion, { 0 }, { 0 }); - - for (MemoryInfo meminfo : memInfos) { - if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) - continue; - else if (searchRegion == SEARCH_REGION_MAIN && - (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && - (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) - continue; - - setLedState(ledOn); - ledOn = !ledOn; - - u64 offset = 0; - u64 bufferSize = 0x40000; - u8 *buffer = new u8[bufferSize]; - while (offset < meminfo.size) { - - if (meminfo.size - offset < bufferSize) - bufferSize = meminfo.size - offset; - - debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); - (*displayDump)->addData(buffer, bufferSize); - - offset += bufferSize; - } - - delete[] buffer; - } - - setLedState(false); -} - -void GuiCheats::searchMemoryValuesSecondary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { - bool ledOn = false; - - MemoryDump *newMemDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::DATA, true); - MemoryDump *addrDump = new MemoryDump(EDIZON_DIR "/memdump3.dat", DumpType::ADDR, true); - u64 dumpOffset = 0; - - for (MemoryInfo meminfo : memInfos) { - if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) - continue; - else if (searchRegion == SEARCH_REGION_MAIN && - (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && - (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) - continue; - - setLedState(ledOn); - ledOn = !ledOn; - - u64 offset = 0; - u64 bufferSize = 0x40000; - u8 *buffer = new u8[bufferSize]; - while (offset < meminfo.size) { - - if (meminfo.size - offset < bufferSize) - bufferSize = meminfo.size - offset; - - debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); - newMemDump->addData(buffer, bufferSize); - - offset += bufferSize; - } - - delete[] buffer; - } - - // Bigger buffers - for (u64 addr = 0; addr < std::min((*displayDump)->size(), newMemDump->size()); addr += dataTypeSizes[searchType]) { - searchValue_t oldValue = { 0 }; - searchValue_t newValue = { 0 }; - (*displayDump)->getData(addr, &oldValue, dataTypeSizes[searchType]); - newMemDump->getData(addr, &newValue, dataTypeSizes[searchType]); - - if (addr % 500 == 0) { - setLedState(ledOn); - ledOn = !ledOn; - } - - switch(searchMode) { - case SEARCH_MODE_SAME: - if (newValue._u64 == oldValue._u64) - addrDump->addData((u8*)&addr, sizeof(u64)); - break; - case SEARCH_MODE_DIFF: - if (newValue._u64 != oldValue._u64) - addrDump->addData((u8*)&addr, sizeof(u64)); - break; - case SEARCH_MODE_INC: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (newValue._s64 > oldValue._s64) - (*displayDump)->addData((u8*)&addr, sizeof(u64)); - } else { - if (newValue._u64 > oldValue._u64) - (*displayDump)->addData((u8*)&addr, sizeof(u64)); - } - break; - case SEARCH_MODE_DEC: - if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { - if (newValue._s64 < oldValue._s64) - (*displayDump)->addData((u8*)&addr, sizeof(u64)); - } else { - if (newValue._u64 < oldValue._u64) - (*displayDump)->addData((u8*)&addr, sizeof(u64)); - } - break; - } - - } - - setLedState(false); -} - -void GuiCheats::searchMemoryValuesTertiary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { - MemoryDump *newMemDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::DATA, true); - MemoryDump *addrDump = new MemoryDump(EDIZON_DIR "/memdump3.dat", DumpType::ADDR, true); - u64 dumpOffset = 0; - - for (MemoryInfo meminfo : memInfos) { - if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) - continue; - else if (searchRegion == SEARCH_REGION_MAIN && - (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && - (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) - continue; - else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) - continue; - - u64 offset = 0; - u64 bufferSize = 0x40000; - u8 *buffer = new u8[bufferSize]; - while (offset < meminfo.size) { - - if (meminfo.size - offset < bufferSize) - bufferSize = meminfo.size - offset; - - debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); - (*displayDump)->addData(buffer, bufferSize); - - offset += bufferSize; - } - - delete[] buffer; - } -} - -/** - * Primary: - * Initial full memory dump regardless of type - * Differentiate between different regions and types - * - * Secondary: - * Second full memory dump regardless of type - * Differentiate between regions and types. (both fix now) - * - * Compare both memory dumps based on type and mode - * Store match addresses into additional file - * Matches should be stored as [MEMADDR][DUMPADDR] for fast comparing later on - * - * Tertiary (Loop infinitely): - * Iterate over match addrs file - * Compare value in memory at [MEMADDR] with value in second memory dump at [DUMPADDR] - * Store match addresses into file (displayDump) - * Dump all values from changed addresses into a file - * Matches should be stored as [MEMADDR][DUMPADDR] for fast comparing later on - */ - -static void _moveLonelyCheats(u8 *buildID, u64 titleID) { - std::stringstream lonelyCheatPath; - std::stringstream realCheatPath; - - std::stringstream buildIDStr; - - for (u8 i = 0; i < 8; i++) - buildIDStr << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)buildID[i]; - - lonelyCheatPath << EDIZON_DIR "/cheats/" << buildIDStr.str() << ".txt"; - - if (access(lonelyCheatPath.str().c_str(), F_OK) == 0) { - realCheatPath << "/atmosphere/titles/" << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << titleID; - mkdir(realCheatPath.str().c_str(), 0777); - realCheatPath << "/cheats/"; - mkdir(realCheatPath.str().c_str(), 0777); - - realCheatPath << buildIDStr.str() << ".txt"; - - rename(lonelyCheatPath.str().c_str(), realCheatPath.str().c_str()); - - (new MessageBox("A new cheat has been added for this title. \n Please restart the game to start using it.", MessageBox::OKAY))->show(); - } -} - -static bool _wrongCheatsPresent(u8 *buildID, u64 titleID) { - std::stringstream ss; - - ss << "/atmosphere/titles/" << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << titleID << "/cheats/"; - - if (!std::filesystem::exists(ss.str())) - return false; - - bool cheatsFolderEmpty = std::filesystem::is_empty(ss.str()); - - for (u8 i = 0; i < 8; i++) - ss << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)buildID[i]; - ss << ".txt"; - - bool realCheatDoesExist = std::filesystem::exists(ss.str()); - - return !(cheatsFolderEmpty || realCheatDoesExist); -} +#include "guis/gui_cheats.hpp" + +#include +#include +#include + +#include +#include + +#include "helpers/util.h" + +#include "edizon_logo_bin.h" + + +static const std::vector dataTypes = { "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "f32", "f64", "ptr" }; +static const std::vector dataTypeSizes = { 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 8 }; +static const std::vector dataTypeMaxValues = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; +static const std::vector dataTypeMinValues = { std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min() }; + +static std::string titleNameStr, tidStr, pidStr, buildIDStr; + +static u32 cheatListOffset = 0; + +static bool _isAddressFrozen(uintptr_t ); +static std::string _getAddressDisplayString(u64 , Debugger *debugger, searchType_t searchType); +static std::string _getValueDisplayString(searchValue_t searchValue, searchType_t searchType); +static void _moveLonelyCheats(u8 *buildID, u64 titleID); +static bool _wrongCheatsPresent(u8 *buildID, u64 titleID); + +GuiCheats::GuiCheats() : Gui() { + + // Check if dmnt:cht is running and we're not on sxos + m_sysmodulePresent = isServiceRunning("dmnt:cht") && !(isServiceRunning("tx") && !isServiceRunning("rnx")); + + m_debugger = new Debugger(); + m_cheats = nullptr; + m_memoryDump = nullptr; + + m_searchValue[0]._u64 = 0; + m_searchValue[1]._u64 = 0; + m_searchType = SEARCH_TYPE_NONE; + m_searchMode = SEARCH_MODE_NONE; + m_searchRegion = SEARCH_REGION_NONE; + + m_cheatCnt = 0; + + if (!m_sysmodulePresent) return; + + dmntchtInitialize(); + dmntchtForceOpenCheatProcess(); + + DmntCheatProcessMetadata metadata; + dmntchtGetCheatProcessMetadata(&metadata); + + m_addressSpaceBaseAddr = metadata.address_space_extents.base; + m_heapBaseAddr = metadata.heap_extents.base; + m_mainBaseAddr = metadata.main_nso_extents.base; + + m_heapSize = metadata.heap_extents.size; + m_mainSize = metadata.main_nso_extents.size; + + memcpy(m_buildID, metadata.main_nso_build_id, 0x20); + + _moveLonelyCheats(m_buildID, m_debugger->getRunningApplicationTID()); + + dmntchtGetCheatCount(&m_cheatCnt); + + if (m_cheatCnt > 0) { + m_cheats = new DmntCheatEntry[m_cheatCnt]; + dmntchtGetCheats(m_cheats, m_cheatCnt, 0, &m_cheatCnt); + } else if (_wrongCheatsPresent(m_buildID, m_debugger->getRunningApplicationTID())) + m_cheatsPresent = true; + + u64 frozenAddressCnt = 0; + dmntchtGetFrozenAddressCount(&frozenAddressCnt); + + if (frozenAddressCnt != 0) { + DmntFrozenAddressEntry frozenAddresses[frozenAddressCnt]; + dmntchtGetFrozenAddresses(frozenAddresses, frozenAddressCnt, 0, nullptr); + + for (u16 i = 0; i < frozenAddressCnt; i++) + m_frozenAddresses.insert({ frozenAddresses[i].address, frozenAddresses[i].value.value }); + + } + + MemoryInfo meminfo = { 0 }; + u64 lastAddr = 0; + + do { + lastAddr = meminfo.addr; + meminfo = m_debugger->queryMemory(meminfo.addr + meminfo.size); + + m_memoryInfo.push_back(meminfo); + } while (lastAddr < meminfo.addr + meminfo.size); + + for (MemoryInfo meminfo : m_memoryInfo) { + if (m_mainBaseAddr == 0x00 && (meminfo.type == MemType_CodeStatic)) + m_mainBaseAddr = meminfo.addr; + + for (u64 addrOffset = meminfo.addr; addrOffset < meminfo.addr + meminfo.size; addrOffset += 0x20000000) { + switch(meminfo.type) { + case MemType_CodeStatic: + case MemType_CodeMutable: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0xFF, 0x00, 0x00, 0xFF); break; + case MemType_SharedMem: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x00, 0xFF, 0x00, 0xFF); break; + case MemType_Heap: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x00, 0x00, 0xFF, 0xFF); break; + case MemType_KernelStack: + case MemType_ThreadLocal: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0xFF, 0xFF, 0x00, 0xFF); break; + case MemType_Unmapped: break; + default: m_memory[addrOffset / 0x20000000] = Gui::makeColor(0x80, 0x80, 0x80, 0xFF); break; + } + } + } + + m_memoryDump = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::UNDEFINED, false); + + if (m_debugger->getRunningApplicationPID() == 0 || m_memoryDump->getDumpInfo().heapBaseAddress != m_heapBaseAddr) { + m_memoryDump->clear(); + + remove(EDIZON_DIR "/memdump2.dat"); + remove(EDIZON_DIR "/memdump3.dat"); + + m_searchType = SEARCH_TYPE_NONE; + m_searchRegion = SEARCH_REGION_NONE; + m_searchValue[0]._u64 = 0; + m_searchValue[1]._u64 = 0; + } else { + m_searchType = m_memoryDump->getDumpInfo().searchDataType; + m_searchRegion = m_memoryDump->getDumpInfo().searchRegion; + m_searchValue[0] = m_memoryDump->getDumpInfo().searchValue[0]; + m_searchValue[1] = m_memoryDump->getDumpInfo().searchValue[1]; + } + + m_memoryDump->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); + + std::stringstream ss; + if (m_debugger->getRunningApplicationTID() != 0) { + if (Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName().length() < 24) + ss << Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName(); + else + ss << Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleName().substr(0, 21) << "..."; + titleNameStr = ss.str(); + ss.str(""); + } else titleNameStr = "Unknown title name!"; + + ss << "TID: " << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << m_debugger->getRunningApplicationTID(); + tidStr = ss.str(); + ss.str(""); + + ss << "PID: " << std::dec << m_debugger->getRunningApplicationPID(); + pidStr = ss.str(); + ss.str(""); + + ss << "BID: "; + for (u8 i = 0; i < 8; i++) + ss << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)m_buildID[i]; + + buildIDStr = ss.str(); + + if (m_cheatCnt == 0) + m_menuLocation = CANDIDATES; + if (m_memoryDump->size() == 0) + m_menuLocation = CHEATS; + + appletSetMediaPlaybackState(true); +} + +GuiCheats::~GuiCheats() { + + if (m_debugger != nullptr) { + delete m_debugger; + } + + if (m_memoryDump != nullptr) + delete m_memoryDump; + + if (m_cheats != nullptr) + delete[] m_cheats; + + if (m_sysmodulePresent) { + dmntchtExit(); + } + + setLedState(false); + appletSetMediaPlaybackState(false); +} + +void GuiCheats::update() { + Gui::update(); +} + +void GuiCheats::draw() { + static u32 splashCnt = 0; + std::stringstream ss; + + Gui::beginDraw(); + + #if SPLASH_ENABLED + + if (!Gui::g_splashDisplayed) { + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x5D, 0x4F, 0x4E, 0xFF)); + Gui::drawImage(Gui::g_framebuffer_width / 2 - 128, Gui::g_framebuffer_height / 2 - 128, 256, 256, edizon_logo_bin, IMAGE_MODE_BGR24); + + if (splashCnt++ >= 70) + Gui::g_splashDisplayed = true; + + Gui::endDraw(); + return; + } + + #endif + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); + + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); + + if (m_debugger->getRunningApplicationPID() == 0) { + Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "\uE12C", ALIGNED_CENTER); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, currTheme.textColor, "A title needs to be running in the background to use the RAM editor. \n Please launch an application and try again.", ALIGNED_CENTER); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E1 Back", ALIGNED_RIGHT); + Gui::endDraw(); + return; + } else if (!m_sysmodulePresent) { + Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "\uE142", ALIGNED_CENTER); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, currTheme.textColor, "EdiZon depends on Atmosphere's dmnt:cht service which doesn't seem to be \n running on this device. Please install a supported CFW to \n use the cheat engine.", ALIGNED_CENTER); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E1 Back", ALIGNED_RIGHT); + Gui::endDraw(); + return; + } + + if (m_memoryDump->size() == 0) { + if (m_frozenAddresses.size() != 0) + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Frozen es \uE0E3 Search RAM \uE0E1 Back", ALIGNED_RIGHT); + else + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E3 Search RAM \uE0E1 Back", ALIGNED_RIGHT); + } else { + if (m_memoryDump->size() > 0) { + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Reset search \uE0E3 Search again \uE0E2 Freeze value \uE0E0 Edit value \uE0E1 Back", ALIGNED_RIGHT); + } + else + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0F0 Reset search \uE0E1 Back", ALIGNED_RIGHT); + } + + Gui::drawRectangle(256, 50, Gui::g_framebuffer_width - 256, 206, currTheme.separatorColor); + + if (m_debugger->getRunningApplicationTID() != 0) + Gui::drawImage(0, 0, 256, 256, Title::g_titles[m_debugger->getRunningApplicationTID()]->getTitleIcon(), IMAGE_MODE_RGB24); + else + Gui::drawRectangle(0, 0, 256, 256, Gui::makeColor(0x00, 0x00, 0xFF, 0xFF)); + + Gui::drawRectangle(660, 65, 20, 20, Gui::makeColor(0xFF, 0x00, 0x00, 0xFF)); // Code + Gui::drawRectangle(660, 85, 20, 20, Gui::makeColor(0x00, 0xFF, 0x00, 0xFF)); // Shared Memory + Gui::drawRectangle(660, 105, 20, 20, Gui::makeColor(0x00, 0x00, 0xFF, 0xFF)); // Heap + Gui::drawRectangle(660, 125, 20, 20, Gui::makeColor(0xFF, 0xFF, 0x00, 0xFF)); // Stack + Gui::drawRectangle(660, 145, 20, 20, Gui::makeColor(0x80, 0x80, 0x80, 0xFF)); // Others + + Gui::drawTextAligned(font14, 700, 62, currTheme.textColor, "Code", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 700, 82, currTheme.textColor, "Shared Memory", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 700, 102, currTheme.textColor, "Heap", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 700, 122, currTheme.textColor, "Stack", ALIGNED_LEFT); + Gui::drawTextAligned(font14, 700, 142, currTheme.textColor, "Others", ALIGNED_LEFT); + + + ss.str(""); + ss << "BASE : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_addressSpaceBaseAddr; + Gui::drawTextAligned(font14, 900, 75, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + ss.str(""); + ss << "HEAP : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_heapBaseAddr; + Gui::drawTextAligned(font14, 900, 105, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + ss.str(""); + ss << "MAIN : 0x" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << m_mainBaseAddr; + Gui::drawTextAligned(font14, 900, 135, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + + + Gui::drawRectangle(256, 50, 394, 137, COLOR_WHITE); + + Gui::drawTextAligned(font20, 280, 70, COLOR_BLACK, titleNameStr.c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font14, 290, 110, COLOR_BLACK, tidStr.c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font14, 290, 130, COLOR_BLACK, pidStr.c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font14, 290, 150, COLOR_BLACK, buildIDStr.c_str(), ALIGNED_LEFT); + + if (Account::g_activeUser != 0) { + ss.str(""); + ss << Account::g_accounts[Account::g_activeUser]->getUserName() << " [ " << std::hex << (u64)(Account::g_activeUser >> 64) << " " << (u64)(Account::g_activeUser & 0xFFFFFFFFFFFFFFFFULL) << " ]"; + Gui::drawTextAligned(font20, 768, 205, currTheme.textColor, ss.str().c_str(), ALIGNED_CENTER); + } + + if (m_cheatCnt > 0) { + Gui::drawRectangle(50, 256, 650, 46 + std::min(static_cast(m_cheatCnt), 8U) * 40, currTheme.textColor); + Gui::drawTextAligned(font14, 375, 262, currTheme.backgroundColor, "Cheats", ALIGNED_CENTER); + Gui::drawShadow(50, 256, 650, 46 + std::min(static_cast(m_cheatCnt), 8U) * 40); + + for (u8 line = cheatListOffset; line < 8 + cheatListOffset; line++) { + if (line >= m_cheatCnt) break; + + ss.str(""); + ss << "\uE070 " << m_cheats[line].definition.readable_name; + + Gui::drawRectangle(52, 300 + (line - cheatListOffset) * 40, 646, 40, (m_selectedEntry == line && m_menuLocation == CHEATS) ? currTheme.highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); + Gui::drawTextAligned(font14, 70, 305 + (line - cheatListOffset) * 40, (m_selectedEntry == line && m_menuLocation == CHEATS) ? COLOR_BLACK : currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + + if (!m_cheats[line].enabled) { + color_t highlightColor = currTheme.highlightColor; + highlightColor.a = 0xFF; + + Gui::drawRectangled(74, 313 + (line - cheatListOffset) * 40, 10, 10, (m_selectedEntry == line && m_menuLocation == CHEATS) ? highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); + } + } + } else if (m_cheatsPresent && m_memoryDump->size() == 0) + Gui::drawTextAligned(font24, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 + 50, currTheme.textColor, "Cheats for this game present but title version or region doesn't match!", ALIGNED_CENTER); + + + if (m_memoryDump->getDumpInfo().dumpType == DumpType::DATA) { + if (m_memoryDump->size() > 0) { + Gui::drawRectangle(Gui::g_framebuffer_width - 552, 256, 500, 366, currTheme.textColor); + Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 302, 262, currTheme.backgroundColor, "Found candidates", ALIGNED_CENTER); + Gui::drawShadow(Gui::g_framebuffer_width - 552, 256, 500, 366 * 40); + Gui::drawRectangle(Gui::g_framebuffer_width - 550, 300, 496, 320, currTheme.separatorColor); + + + ss.str(""); + ss << (static_cast(m_memoryDump->size()) / (0x100000)) << "MB dumped"; + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 302, 450, currTheme.textColor, ss.str().c_str(), ALIGNED_CENTER); + } + } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { + if (m_memoryDump->size() > 0) { + Gui::drawRectangle(Gui::g_framebuffer_width - 552, 256, 500, 46 + std::min(static_cast(m_memoryDump->size() / sizeof(u64)), 8U) * 40, currTheme.textColor); + Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 302, 262, currTheme.backgroundColor, "Found candidates", ALIGNED_CENTER); + Gui::drawShadow(Gui::g_framebuffer_width - 552, 256, 500, 46 + std::min(static_cast(m_memoryDump->size() / sizeof(u64)), 8U) * 40); + } + + for (u8 line = 0; line < 8; line++) { + if (line >= (m_memoryDump->size() / sizeof(u64))) break; + + ss.str(""); + + if (line < 7 && (m_memoryDump->size() / sizeof(u64)) != 8) { + u64 address = 0; + m_memoryDump->getData(line * sizeof(u64), &address, sizeof(u64)); + + if (address >= m_memoryDump->getDumpInfo().heapBaseAddress && address < (m_memoryDump->getDumpInfo().heapBaseAddress + m_memoryDump->getDumpInfo().heapSize)) + ss << "[ HEAP + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().heapBaseAddress) << " ]"; + else if (address >= m_memoryDump->getDumpInfo().mainBaseAddress && address < (m_memoryDump->getDumpInfo().mainBaseAddress + m_memoryDump->getDumpInfo().mainSize)) + ss << "[ MAIN + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().mainBaseAddress) << " ]"; + else + ss << "[ BASE + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (address - m_memoryDump->getDumpInfo().addrSpaceBaseAddress) << " ]"; + + ss << " ( " << _getAddressDisplayString(address, m_debugger, (searchType_t)m_searchType) << " )"; + + if (m_frozenAddresses.find(address) != m_frozenAddresses.end()) + ss << " \uE130"; + } + else + ss << "And " << std::dec << ((m_memoryDump->size() / sizeof(u64)) - 8) << " others..."; + + Gui::drawRectangle(Gui::g_framebuffer_width - 550, 300 + line * 40, 496, 40, (m_selectedEntry == line && m_menuLocation == CANDIDATES) ? currTheme.highlightColor : line % 2 == 0 ? currTheme.backgroundColor : currTheme.separatorColor); + Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 530, 305 + line * 40, (m_selectedEntry == line && m_menuLocation == CANDIDATES) ? COLOR_BLACK : currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + } + } + + Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 256); + Gui::drawShadow(256, 50, Gui::g_framebuffer_width, 136); + + for (u16 x = 0; x < 1024; x++) + Gui::drawRectangle(256 + x, 0, 2, 50, m_memory[x]); + + drawSearchRAMMenu(); + + Gui::endDraw(); +} + +void GuiCheats::drawSearchRAMMenu() { + static u32 cursorBlinkCnt = 0; + u32 strWidth = 0; + std::stringstream ss; + + if (m_searchMenuLocation == SEARCH_NONE) return; + + Gui::drawRectangled(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x00, 0x00, 0x00, 0xA0)); + + Gui::drawRectangle(50, 50, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.backgroundColor); + Gui::drawRectangle(100, 135, Gui::g_framebuffer_width - 200, 1, currTheme.textColor); + Gui::drawText(font24, 120, 70, currTheme.textColor, "\uE132 Search Memory"); + + Gui::drawTextAligned(font20, 100, 160, currTheme.textColor, "\uE149 \uE0A4", ALIGNED_LEFT); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, 160, currTheme.textColor, "\uE0A5 \uE14A", ALIGNED_RIGHT); + + Gui::drawTextAligned(font20, 260, 160, m_searchMenuLocation == SEARCH_TYPE ? currTheme.selectedColor : currTheme.textColor, "TYPE", ALIGNED_CENTER); + Gui::drawTextAligned(font20, 510, 160, m_searchMenuLocation == SEARCH_MODE ? currTheme.selectedColor : currTheme.textColor, "MODE", ALIGNED_CENTER); + Gui::drawTextAligned(font20, 760, 160, m_searchMenuLocation == SEARCH_REGION ? currTheme.selectedColor : currTheme.textColor, "REGION", ALIGNED_CENTER); + Gui::drawTextAligned(font20, 1010, 160, m_searchMenuLocation == SEARCH_VALUE ? currTheme.selectedColor : currTheme.textColor, "VALUE", ALIGNED_CENTER); + + static const char* const typeNames[] = { "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "flt", "dbl", "void*" }; + static const char* const modeNames[] = { "==", "!=", ">", ">=", "<", "<=", "A..B", "SAME", "DIFF", "+ +", "- -" }; + static const char* const regionNames[] = { "HEAP", "MAIN", "HEAP + MAIN", "RAM" }; + + switch (m_searchMenuLocation) { + case SEARCH_TYPE: + for (u8 i = 0; i < 11; i++) { + if (m_selectedEntry == i) + Gui::drawRectangled(356 + (i / 2) * 100, 220 + (i % 2) * 100, 90, 90, m_searchType == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); + + Gui::drawRectangled(361 + (i / 2) * 100, 225 + (i % 2) * 100, 80, 80, currTheme.separatorColor); + Gui::drawTextAligned(font20, 400 + (i / 2) * 100, 250 + (i % 2) * 100, currTheme.textColor, typeNames[i], ALIGNED_CENTER); + } + + Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the data type of the value you’re searching here. The prefix [u] means unsigned (positive integers), [s] means \n" + "signed (positive and negative integers), [flt] is for floating point numbers (rational numbers), [dbl] is for double (bigger \n" + "rational numbers) and [void*] stands for pointer (link to another memory ) which is useful for creating cheats. The \n" + "number that follows is the number of bits used in memory which determines the maximum value. Choose the data type that \n" + "best fits for the type of data you’re looking for.", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + + break; + case SEARCH_MODE: + for (u8 i = 0; i < 11; i++) { + if (m_selectedEntry == i) + Gui::drawRectangled(356 + (i / 2) * 100, 220 + (i % 2) * 100, 90, 90, m_searchMode == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); + + Gui::drawRectangled(361 + (i / 2) * 100, 225 + (i % 2) * 100, 80, 80, currTheme.separatorColor); + Gui::drawTextAligned(font20, 400 + (i / 2) * 100, 250 + (i % 2) * 100, currTheme.textColor, modeNames[i], ALIGNED_CENTER); + } + + Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the mode you want to use for finding values. With these modes EdiZon will search for values that are equal to [==], \n" + "not equal to [!=], greater than [>], greater than or equal to [>=], less than [<], or less than or equal to [<=] the value \n" + "that you input. [A : B] allows you to set a (min : max) range of values, SAME and DIFF search allows you to find values that \n" + "stayed the same or changed since the last search, [+ +] and [- -] checks for values that increased or decreased since the \n" + "previous search.", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + break; + case SEARCH_REGION: + for (u8 i = 0; i < 4; i++) { + if (m_selectedEntry == i) + Gui::drawRectangled((Gui::g_framebuffer_width / 2) - 155, 215 + i * 70, 310, 70, m_searchRegion == static_cast(i) ? currTheme.selectedColor : currTheme.highlightColor); + + Gui::drawRectangled((Gui::g_framebuffer_width / 2) - 150, 220 + i * 70, 300, 60, currTheme.separatorColor); + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 235 + i * 70, currTheme.textColor, regionNames[i], ALIGNED_CENTER); + } + + + Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the memory region you want to search in. HEAP contains dynamically allocated values and will be where the majority of \n" + "values worth changing will be found. MAIN contains global variables and instructions for game operation. You may find some \n" + "values here but it’s mainly for finding pointers to HEAP values or changing game code. RAM will search the entirety of the Games \n" + "used memory including memory shared memory and resources. Should only be used as a final resort as this will be extremely slow. \n", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + break; + case SEARCH_VALUE: + Gui::drawTextAligned(font14, Gui::g_framebuffer_width / 2, 500, currTheme.textColor, "Set the value you want to search for. The value(s) you enter here will depend on what options you've chosen in the \n" + "first three sections. Either it's the exact integer you want to search for, a floating point number or even two values that \n" + "will be used as range.", ALIGNED_CENTER); + + //Gui::drawRectangle(300, 250, Gui::g_framebuffer_width - 600, 80, currTheme.separatorColor); + Gui::drawRectangle(300, 327, Gui::g_framebuffer_width - 600, 3, currTheme.textColor); + if (m_searchValueFormat == FORMAT_DEC) + ss << _getValueDisplayString(m_searchValue[0], m_searchType); + else if (m_searchValueFormat == FORMAT_HEX) + ss << "0x" << std::uppercase << std::hex << m_searchValue[0]._u64; + + Gui::getTextDimensions(font20, ss.str().c_str(), &strWidth, nullptr); + Gui::drawTextAligned(font20, 310, 285, currTheme.textColor, ss.str().c_str(), ALIGNED_LEFT); + + if (cursorBlinkCnt++ % 20 > 10 && m_selectedEntry == 0) + Gui::drawRectangled(312 + strWidth, 285, 3, 35, currTheme.highlightColor); + + if (m_searchValueFormat == FORMAT_DEC) + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E2 Hexadecimal view \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + else if (m_searchValueFormat == FORMAT_HEX) + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 100, currTheme.textColor, "\uE0E2 Decimal view \uE0E1 Back \uE0E0 OK", ALIGNED_RIGHT); + + if (m_selectedEntry == 1) + Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 155, 345, 310, 90, currTheme.highlightColor); + + if (m_searchType != SEARCH_TYPE_NONE && m_searchMode != SEARCH_MODE_NONE && m_searchRegion != SEARCH_REGION_NONE) { + Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 150, 350, 300, 80, currTheme.selectedColor); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 375, currTheme.backgroundColor, "Search Now!", ALIGNED_CENTER); + } + else { + Gui::drawRectangled(Gui::g_framebuffer_width / 2 - 150, 350, 300, 80, currTheme.selectedButtonColor); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, 375, currTheme.separatorColor, "Search Now!", ALIGNED_CENTER); + } + + + break; + case SEARCH_NONE: break; + } +} + +void GuiCheats::onInput(u32 kdown) { + if (kdown & KEY_B) { + + if (m_searchMenuLocation == SEARCH_NONE) { + Gui::g_nextGui = GUI_MAIN; + return; + } + else if (m_searchMenuLocation == SEARCH_TYPE) { + if (m_searchType != SEARCH_TYPE_NONE && m_memoryDump->size() == 0) + m_searchType = SEARCH_TYPE_NONE; + else + m_searchMenuLocation = SEARCH_NONE; + } + else if (m_searchMenuLocation == SEARCH_MODE) { + if (m_searchMode != SEARCH_MODE_NONE) + m_searchMode = SEARCH_MODE_NONE; + else + m_searchMenuLocation = SEARCH_NONE; + } + else if (m_searchMenuLocation == SEARCH_REGION) { + if (m_searchRegion != SEARCH_REGION_NONE && m_memoryDump->size() == 0) + m_searchRegion = SEARCH_REGION_NONE; + else + m_searchMenuLocation = SEARCH_NONE; + } + else if (m_searchMenuLocation == SEARCH_VALUE) + m_searchMenuLocation = SEARCH_NONE; + } + + if (m_debugger->getRunningApplicationPID() == 0) + return; + + if (m_searchMenuLocation == SEARCH_NONE) { + if (kdown & KEY_UP) { + if (m_selectedEntry > 0) + m_selectedEntry--; + + if (m_menuLocation == CHEATS) + if (m_selectedEntry == cheatListOffset && cheatListOffset > 0) + cheatListOffset--; + } + + if (kdown & KEY_DOWN) { + if (m_menuLocation == CANDIDATES) { + if (m_selectedEntry < 7 && m_selectedEntry < ((m_memoryDump->size() / sizeof(u64)) - 1)) + m_selectedEntry++; + } else { + if (m_selectedEntry < (m_cheatCnt - 1)) + m_selectedEntry++; + + if (m_selectedEntry == (cheatListOffset + 7) && cheatListOffset < (m_cheatCnt - 8)) + cheatListOffset++; + } + } + + if (m_memoryDump->size() > 0) { + if (kdown & KEY_LEFT) + if (m_cheatCnt > 0) { + m_menuLocation = CHEATS; + m_selectedEntry = 0; + cheatListOffset = 0; + } + + if (kdown & KEY_RIGHT) { + m_menuLocation = CANDIDATES; + m_selectedEntry = 0; + cheatListOffset = 0; + } + } + + if (m_menuLocation == CANDIDATES) { /* Candidates menu */ + if (m_memoryDump->size() > 0) { + if (kdown & KEY_X && m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { + u64 address = 0; + m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); + if (!_isAddressFrozen(address)) { + u64 outValue; + + if (R_SUCCEEDED(dmntchtEnableFrozenAddress(address, dataTypeSizes[m_searchType], &outValue))) { + (new Snackbar("Froze variable!"))->show(); + m_frozenAddresses.insert({ address, outValue }); + } + else + (new Snackbar("Failed to freeze variable!"))->show(); + } + else { + if (R_SUCCEEDED(dmntchtDisableFrozenAddress(address))) { + (new Snackbar("Unfroze variable!"))->show(); + m_frozenAddresses.erase(address); + } + else + (new Snackbar("Failed to unfreeze variable!"))->show(); + } + } + + if (kdown & KEY_A && m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { + u64 address = 0; + m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); + + if (m_selectedEntry < 7) { + char input[16]; + char initialString[21]; + + strcpy(initialString, _getAddressDisplayString(address, m_debugger, m_searchType).c_str()); + + if (Gui::requestKeyboardInput("Enter value", "Enter a value that should get written at this .", initialString, SwkbdType::SwkbdType_NumPad, input, 15)) { + m_debugger->pokeMemory(dataTypeSizes[m_searchType], address, atol(input)); + } + } + else if ((m_memoryDump->size() / sizeof(u64)) < 25) { + std::vector options; + options.clear(); + + std::stringstream ss; + for (u32 i = 7; i < (m_memoryDump->size() / sizeof(u64)); i++) { //TODO: i? + m_memoryDump->getData(m_selectedEntry * sizeof(u64), &address, sizeof(u64)); + ss.str(""); + ss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << address; + + ss << " (" << _getAddressDisplayString(address, m_debugger, m_searchType); + + options.push_back(ss.str()); + printf("%s\n", ss.str().c_str()); + } + + (new ListSelector("Edit value at ", "\uE0E0 Edit value \uE0E1 Back", options))->setInputAction([&](u32 k, u16 selectedItem) { + if (k & KEY_A) { + char input[16]; + char initialString[21]; + u64 selectedAddress; + + m_memoryDump->getData((selectedItem + 7) * sizeof(u64), &selectedAddress, sizeof(u64)); + + strcpy(initialString, _getAddressDisplayString(selectedAddress, m_debugger, m_searchType).c_str()); + + if (Gui::requestKeyboardInput("Enter value", "Enter a value for which the game's memory should be searched.", initialString, SwkbdType::SwkbdType_NumPad, input, 15)) { + u64 value = atol(input); + if (value > dataTypeMaxValues[m_searchType] || value < dataTypeMinValues[m_searchType]) { + (new Snackbar("Entered value isn't inside the range of this data type. Please enter a different value."))->show(); + return; + } + + m_memoryDump->getData((m_selectedEntry) * sizeof(u64), &selectedAddress, sizeof(u64)); + m_debugger->pokeMemory(dataTypeSizes[m_searchType], selectedAddress, value); + } + } + })->show(); + } else (new Snackbar("Too many addresses! Narrow down the selection before editing."))->show(); + } + } + } else { /* Cheats menu */ + if (kdown & KEY_A) { + if (m_cheatCnt == 0) return; + + dmntchtToggleCheat(m_cheats[m_selectedEntry].cheat_id); + u64 cheatCnt = 0; + + dmntchtGetCheatCount(&cheatCnt); + if (cheatCnt > 0) { + delete[] m_cheats; + m_cheats = new DmntCheatEntry[cheatCnt]; + dmntchtGetCheats(m_cheats, cheatCnt, 0, &m_cheatCnt); + } + } + } + + if (kdown & KEY_MINUS) { + if (m_memoryDump->size() == 0) { + std::vector options; + + if (m_frozenAddresses.size() == 0) + return; + + std::stringstream ss; + for (auto [addr, value] : m_frozenAddresses) { + ss << "[ BASE + 0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(10) << (addr - m_addressSpaceBaseAddr) << " ] "; + ss << "( " << std::dec << value << " )"; + options.push_back(ss.str()); + ss.str(""); + } + + (new ListSelector("Frozen Addresses", "\uE0E0 Unfreeze \uE0E1 Back", options))->setInputAction([&](u32 k, u16 selectedItem) { + if (k & KEY_A) { + auto itr = m_frozenAddresses.begin(); + std::advance(itr, selectedItem); + + dmntchtDisableFrozenAddress(itr->first); + m_frozenAddresses.erase(itr->first); + } + })->show(); + } else { + m_memoryDump->clear(); + remove(EDIZON_DIR "/memdump1.dat"); + remove(EDIZON_DIR "/memdump2.dat"); + remove(EDIZON_DIR "/memdump3.dat"); + + m_searchType = SEARCH_TYPE_NONE; + m_searchMode = SEARCH_MODE_NONE; + m_searchRegion = SEARCH_REGION_NONE; + m_searchValue[0]._u64 = 0; + m_searchValue[1]._u64 = 0; + + m_menuLocation = CHEATS; + } + } + + if (kdown & KEY_Y) { + if (m_searchMenuLocation == SEARCH_NONE) { + m_searchMenuLocation = SEARCH_TYPE; + m_selectedEntry = m_searchType == SEARCH_TYPE_NONE ? 0 : m_searchType; + cheatListOffset = 0; + } + } + } + else { + if ((m_searchMenuLocation == SEARCH_TYPE && m_searchType == SEARCH_TYPE_NONE) || + (m_searchMenuLocation == SEARCH_MODE && m_searchMode == SEARCH_MODE_NONE) || + (m_searchMenuLocation == SEARCH_REGION && m_searchRegion == SEARCH_REGION_NONE) || + (m_searchMenuLocation == SEARCH_VALUE)) { + if (kdown & KEY_UP) { + switch (m_searchMenuLocation) { + case SEARCH_TYPE: [[fallthrough]] + case SEARCH_MODE: + if (m_selectedEntry % 2 == 1) + m_selectedEntry--; + break; + case SEARCH_REGION: + if (m_selectedEntry > 0) + m_selectedEntry--; + break; + case SEARCH_VALUE: + m_selectedEntry = 0; + break; + case SEARCH_NONE: break; + } + } + + if (kdown & KEY_DOWN) { + switch (m_searchMenuLocation) { + case SEARCH_TYPE: [[fallthrough]] + case SEARCH_MODE: + if ((m_selectedEntry + 1) < 10 && m_selectedEntry % 2 == 0) + m_selectedEntry++; + break; + case SEARCH_REGION: + if (m_selectedEntry < 3) + m_selectedEntry++; + break; + case SEARCH_VALUE: + if (m_searchType != SEARCH_TYPE_NONE && m_searchMode != SEARCH_MODE_NONE && m_searchRegion != SEARCH_REGION_NONE) + m_selectedEntry = 1; + break; + case SEARCH_NONE: break; + } + } + + if (kdown & KEY_LEFT) { + switch (m_searchMenuLocation) { + case SEARCH_TYPE: [[fallthrough]] + case SEARCH_MODE: + if (m_selectedEntry >= 2) + m_selectedEntry -= 2; + break; + case SEARCH_REGION: + break; + case SEARCH_VALUE: + break; + case SEARCH_NONE: break; + } + } + + if (kdown & KEY_RIGHT) { + switch (m_searchMenuLocation) { + case SEARCH_TYPE: [[fallthrough]] + case SEARCH_MODE: + if (m_selectedEntry <= 8) + m_selectedEntry += 2; + break; + case SEARCH_REGION: + break; + case SEARCH_VALUE: + break; + case SEARCH_NONE: break; + } + } + + if (kdown & KEY_A) { + if (m_searchMenuLocation == SEARCH_TYPE) + m_searchType = static_cast(m_selectedEntry); + else if (m_searchMenuLocation == SEARCH_REGION) + m_searchRegion = static_cast(m_selectedEntry); + else if (m_searchMenuLocation == SEARCH_MODE) + m_searchMode = static_cast(m_selectedEntry); + else if (m_searchMenuLocation == SEARCH_VALUE) { + if (m_selectedEntry == 0) { + char str[0x21]; + Gui::requestKeyboardInput("Enter the value you want to search for", "Based on your previously chosen options, EdiZon will expect different input here.", "", m_searchValueFormat == FORMAT_DEC ? SwkbdType_NumPad : SwkbdType_QWERTY, str, 0x20); + + if (std::string(str) == "") return; + + if (m_searchValueFormat == FORMAT_HEX) { + m_searchValue[0]._u64 = static_cast(std::stoul(str, nullptr, 16)); + } else { + switch(m_searchType) { + case SEARCH_TYPE_UNSIGNED_8BIT: + m_searchValue[0]._u8 = static_cast(std::stoul(str, nullptr, 0)); + break; + case SEARCH_TYPE_UNSIGNED_16BIT: + m_searchValue[0]._u16 = static_cast(std::stoul(str, nullptr, 0)); + break; + case SEARCH_TYPE_UNSIGNED_32BIT: + m_searchValue[0]._u32 = static_cast(std::stoul(str, nullptr, 0)); + break; + case SEARCH_TYPE_UNSIGNED_64BIT: + m_searchValue[0]._u64 = static_cast(std::stoul(str, nullptr, 0)); + break; + case SEARCH_TYPE_SIGNED_8BIT: + m_searchValue[0]._s8 = static_cast(std::stol(str, nullptr, 0)); + break; + case SEARCH_TYPE_SIGNED_16BIT: + m_searchValue[0]._s16 = static_cast(std::stol(str, nullptr, 0)); + break; + case SEARCH_TYPE_SIGNED_32BIT: + m_searchValue[0]._s32 = static_cast(std::stol(str, nullptr, 0)); + break; + case SEARCH_TYPE_SIGNED_64BIT: + m_searchValue[0]._s64 = static_cast(std::stol(str, nullptr, 0)); + break; + case SEARCH_TYPE_FLOAT_32BIT: + m_searchValue[0]._f32 = static_cast(std::stof(str)); + break; + case SEARCH_TYPE_FLOAT_64BIT: + m_searchValue[0]._f64 = static_cast(std::stod(str)); + break; + case SEARCH_TYPE_POINTER: + m_searchValue[0]._u64 = static_cast(std::stol(str)); + break; + case SEARCH_TYPE_NONE: break; + } + } + } else if (m_selectedEntry == 1) { + (new MessageBox("Traversing title memory.\n \nThis may take a while...", MessageBox::NONE))->show(); + requestDraw(); + + overclockSystem(true); + + if (m_searchMode == SEARCH_MODE_SAME || m_searchMode == SEARCH_MODE_DIFF || m_searchMode == SEARCH_MODE_INC || m_searchMode == SEARCH_MODE_DEC) { + if (m_memoryDump->size() == 0) { + delete m_memoryDump; + GuiCheats::searchMemoryValuesPrimary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); + } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::DATA) { + GuiCheats::searchMemoryValuesSecondary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); + delete m_memoryDump; + + remove(EDIZON_DIR "/memdump1.dat"); + rename(EDIZON_DIR "/memdump3.dat", EDIZON_DIR "/memdump1.dat"); + + m_memoryDump = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::ADDR, false); + } else if (m_memoryDump->getDumpInfo().dumpType == DumpType::ADDR) { + GuiCheats::searchMemoryValuesTertiary(m_debugger, m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); + } + } else { + if (m_memoryDump->size() == 0) { + delete m_memoryDump; + GuiCheats::searchMemoryAddressesPrimary(m_debugger, m_searchValue[0], m_searchValue[1], m_searchType, m_searchMode, m_searchRegion, &m_memoryDump, m_memoryInfo); + } else { + GuiCheats::searchMemoryAddressesSecondary(m_debugger, m_searchValue[0], m_searchValue[1], m_searchType, m_searchMode, &m_memoryDump); + } + } + + overclockSystem(false); + + Gui::g_currMessageBox->hide(); + + m_searchMenuLocation = SEARCH_NONE; + m_searchMode = SEARCH_MODE_NONE; + } + } + } + } + + if (kdown & KEY_X) { + if (m_searchMenuLocation == SEARCH_VALUE) { + if (m_searchValueFormat == FORMAT_DEC) + m_searchValueFormat = FORMAT_HEX; + else + m_searchValueFormat = FORMAT_DEC; + } + } + + if (kdown & KEY_L) { + if (m_searchMenuLocation == SEARCH_VALUE) { + m_searchMenuLocation = SEARCH_REGION; + m_selectedEntry = m_searchRegion == SEARCH_REGION_NONE ? 0 : static_cast(m_searchRegion); + } + else if (m_searchMenuLocation == SEARCH_REGION) { + m_searchMenuLocation = SEARCH_MODE; + m_selectedEntry = m_searchMode == SEARCH_MODE_NONE ? 0 : static_cast(m_searchMode); + } + else if (m_searchMenuLocation == SEARCH_MODE) { + m_searchMenuLocation = SEARCH_TYPE; + m_selectedEntry = m_searchType == SEARCH_TYPE_NONE ? 0 : static_cast(m_searchType); + } + } + + if (kdown & KEY_R) { + if (m_searchMenuLocation == SEARCH_TYPE) { + m_searchMenuLocation = SEARCH_MODE; + m_selectedEntry = m_searchMode == SEARCH_MODE_NONE ? 0 : static_cast(m_searchMode); + } + else if (m_searchMenuLocation == SEARCH_MODE) { + m_searchMenuLocation = SEARCH_REGION; + m_selectedEntry = m_searchRegion == SEARCH_REGION_NONE ? 0 : static_cast(m_searchRegion); + } + else if (m_searchMenuLocation == SEARCH_REGION) { + m_searchMenuLocation = SEARCH_VALUE; + m_selectedEntry = 0; + } + } + + } +} + +void GuiCheats::onTouch(touchPosition &touch) { + +} + +void GuiCheats::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} + +static bool _isAddressFrozen(uintptr_t address) { + DmntFrozenAddressEntry *es; + u64 Cnt = 0; + bool frozen = false; + + dmntchtGetFrozenAddressCount(&Cnt); + + if (Cnt != 0) { + es = new DmntFrozenAddressEntry[Cnt]; + dmntchtGetFrozenAddresses(es, Cnt, 0, nullptr); + + for (u64 i = 0; i < Cnt; i++) { + if (es[i].address == address) { + frozen = true; + break; + } + } + } + + return frozen; +} + +static std::string _getAddressDisplayString(u64 address, Debugger *debugger, searchType_t searchType) { + std::stringstream ss; + + searchValue_t searchValue; + searchValue._u64 = debugger->peekMemory(address); + + switch(searchType) { + case SEARCH_TYPE_UNSIGNED_8BIT: + ss << std::dec << static_cast(searchValue._u8); + break; + case SEARCH_TYPE_UNSIGNED_16BIT: + ss << std::dec << static_cast(searchValue._u16); + break; + case SEARCH_TYPE_UNSIGNED_32BIT: + ss << std::dec << static_cast(searchValue._u32); + break; + case SEARCH_TYPE_UNSIGNED_64BIT: + ss << std::dec << static_cast(searchValue._u64); + break; + case SEARCH_TYPE_SIGNED_8BIT: + ss << std::dec << static_cast(searchValue._s8); + break; + case SEARCH_TYPE_SIGNED_16BIT: + ss << std::dec << static_cast(searchValue._s16); + break; + case SEARCH_TYPE_SIGNED_32BIT: + ss << std::dec << static_cast(searchValue._s32); + break; + case SEARCH_TYPE_SIGNED_64BIT: + ss << std::dec << static_cast(searchValue._s64); + break; + case SEARCH_TYPE_FLOAT_32BIT: + ss << std::dec << searchValue._f32; + break; + case SEARCH_TYPE_FLOAT_64BIT: + ss << std::dec << searchValue._f64; + break; + case SEARCH_TYPE_POINTER: + ss << std::dec << searchValue._u64; + break; + case SEARCH_TYPE_NONE: break; + } + + return ss.str(); +} + +static std::string _getValueDisplayString(searchValue_t searchValue, searchType_t searchType) { + std::stringstream ss; + + switch(searchType) { + case SEARCH_TYPE_UNSIGNED_8BIT: + ss << std::dec << static_cast(searchValue._u8); + break; + case SEARCH_TYPE_UNSIGNED_16BIT: + ss << std::dec << static_cast(searchValue._u16); + break; + case SEARCH_TYPE_UNSIGNED_32BIT: + ss << std::dec << static_cast(searchValue._u32); + break; + case SEARCH_TYPE_UNSIGNED_64BIT: + ss << std::dec << static_cast(searchValue._u64); + break; + case SEARCH_TYPE_SIGNED_8BIT: + ss << std::dec << static_cast(searchValue._s8); + break; + case SEARCH_TYPE_SIGNED_16BIT: + ss << std::dec << static_cast(searchValue._s16); + break; + case SEARCH_TYPE_SIGNED_32BIT: + ss << std::dec << static_cast(searchValue._s32); + break; + case SEARCH_TYPE_SIGNED_64BIT: + ss << std::dec << static_cast(searchValue._s64); + break; + case SEARCH_TYPE_FLOAT_32BIT: + ss.precision(15); + ss << std::dec << searchValue._f32; + break; + case SEARCH_TYPE_FLOAT_64BIT: + ss.precision(15); + ss << std::dec << searchValue._f64; + break; + case SEARCH_TYPE_POINTER: + ss << std::dec << searchValue._u64; + break; + case SEARCH_TYPE_NONE: break; + } + + return ss.str(); +} + +void GuiCheats::searchMemoryAddressesPrimary(Debugger *debugger, searchValue_t searchValue1, searchValue_t searchValue2, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { + (*displayDump) = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::ADDR, true); + (*displayDump)->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); + (*displayDump)->setSearchParams(searchType, searchMode, searchRegion, searchValue1, searchValue2); + + bool ledOn = false; + + for (MemoryInfo meminfo : memInfos) { + if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) + continue; + else if (searchRegion == SEARCH_REGION_MAIN && + (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && + (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) + continue; + + setLedState(ledOn); + ledOn = !ledOn; + + u64 offset = 0; + u64 bufferSize = 0x10000; + u8 *buffer = new u8[bufferSize]; + while (offset < meminfo.size) { + + if (meminfo.size - offset < bufferSize) + bufferSize = meminfo.size - offset; + + debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); + + searchValue_t realValue = { 0 }; + for (u32 i = 0; i < bufferSize; i += dataTypeSizes[searchType]) { + u64 address = meminfo.addr + offset + i; + memset(&realValue, 0, 8); + memcpy(&realValue, buffer + i, dataTypeSizes[searchType]); + + switch(searchMode) { + case SEARCH_MODE_EQ: + if (realValue._s64 == searchValue1._s64) { + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + break; + case SEARCH_MODE_NEQ: + if (realValue._s64 != searchValue1._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_GT: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (realValue._s64 > searchValue1._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } else { + if (realValue._u64 > searchValue1._u64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + break; + case SEARCH_MODE_GTE: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (realValue._s64 >= searchValue1._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } else { + if (realValue._u64 >= searchValue1._u64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + break; + case SEARCH_MODE_LT: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (realValue._s64 < searchValue1._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } else { + if (realValue._u64 < searchValue1._u64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + break; + case SEARCH_MODE_LTE: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (realValue._s64 <= searchValue1._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } else { + if (realValue._u64 <= searchValue1._u64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + break; + case SEARCH_MODE_RANGE: + if (realValue._s64 >= searchValue1._s64 && realValue._s64 <= searchValue2._s64) + (*displayDump)->addData((u8*)&address, sizeof(u64)); + break; + } + } + + offset += bufferSize; + } + + delete[] buffer; + } + + setLedState(false); + + (*displayDump)->flushBuffer(); +} + +void GuiCheats::searchMemoryAddressesSecondary(Debugger *debugger, searchValue_t searchValue1, searchValue_t searchValue2, searchType_t searchType, searchMode_t searchMode, MemoryDump **displayDump) { + MemoryDump *newDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::ADDR, true); + bool ledOn = false; + + for (size_t i = 0; i < ((*displayDump)->size() / sizeof(u64)); i++) { + searchValue_t value = { 0 }; + u64 address = 0; + (*displayDump)->getData(i * sizeof(u64), &address, sizeof(u64)); + + debugger->readMemory(&value, dataTypeSizes[searchType], address); + + if (i % 50 == 0) { + setLedState(ledOn); + ledOn = !ledOn; + } + + switch(searchMode) { + case SEARCH_MODE_EQ: + if (value._s64 == searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_NEQ: + if (value._s64 != searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_GT: + if (value._s64 > searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_GTE: + if (value._s64 >= searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_LT: + if (value._s64 < searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_LTE: + if (value._s64 <= searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_RANGE: + if (value._s64 >= searchValue1._s64 && value._s64 <= searchValue2._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_SAME: + if (value._s64 == searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_DIFF: + if (value._s64 != searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_INC: + if (value._s64 > searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_DEC: + if (value._s64 < searchValue1._s64) + newDump->addData((u8*)&address, sizeof(u64)); + break; + case SEARCH_MODE_NONE: break; + } + } + + if (newDump->size() > 0) { + (*displayDump)->clear(); + (*displayDump)->setSearchParams(searchType, searchMode, (*displayDump)->getDumpInfo().searchRegion, searchValue1, searchValue2); + (*displayDump)->setDumpType(DumpType::ADDR); + + for (size_t i = 0; i < (newDump->size() / sizeof(u64)); i++) { + u64 address = 0; + + newDump->getData(i * sizeof(u64), &address, sizeof(u64)); + (*displayDump)->addData((u8*)&address, sizeof(u64)); + } + + (*displayDump)->flushBuffer(); + } else { + (new Snackbar("None of values changed to the entered one!"))->show(); + } + + setLedState(false); + + delete newDump; + + remove(EDIZON_DIR "/memdump2.dat"); +} + +void GuiCheats::searchMemoryValuesPrimary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { + bool ledOn = false; + + searchValue_t zeroValue; + zeroValue._u64 = 0; + + (*displayDump) = new MemoryDump(EDIZON_DIR "/memdump1.dat", DumpType::DATA, true); + (*displayDump)->setBaseAddresses(m_addressSpaceBaseAddr, m_heapBaseAddr, m_mainBaseAddr, m_heapSize, m_mainSize); + (*displayDump)->setSearchParams(searchType, searchMode, searchRegion, { 0 }, { 0 }); + + for (MemoryInfo meminfo : memInfos) { + if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) + continue; + else if (searchRegion == SEARCH_REGION_MAIN && + (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && + (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) + continue; + + setLedState(ledOn); + ledOn = !ledOn; + + u64 offset = 0; + u64 bufferSize = 0x40000; + u8 *buffer = new u8[bufferSize]; + while (offset < meminfo.size) { + + if (meminfo.size - offset < bufferSize) + bufferSize = meminfo.size - offset; + + debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); + (*displayDump)->addData(buffer, bufferSize); + + offset += bufferSize; + } + + delete[] buffer; + } + + setLedState(false); +} + +void GuiCheats::searchMemoryValuesSecondary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { + bool ledOn = false; + + MemoryDump *newMemDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::DATA, true); + MemoryDump *addrDump = new MemoryDump(EDIZON_DIR "/memdump3.dat", DumpType::ADDR, true); + u64 dumpOffset = 0; + + for (MemoryInfo meminfo : memInfos) { + if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) + continue; + else if (searchRegion == SEARCH_REGION_MAIN && + (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && + (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) + continue; + + setLedState(ledOn); + ledOn = !ledOn; + + u64 offset = 0; + u64 bufferSize = 0x40000; + u8 *buffer = new u8[bufferSize]; + while (offset < meminfo.size) { + + if (meminfo.size - offset < bufferSize) + bufferSize = meminfo.size - offset; + + debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); + newMemDump->addData(buffer, bufferSize); + + offset += bufferSize; + } + + delete[] buffer; + } + + // Bigger buffers + for (u64 addr = 0; addr < std::min((*displayDump)->size(), newMemDump->size()); addr += dataTypeSizes[searchType]) { + searchValue_t oldValue = { 0 }; + searchValue_t newValue = { 0 }; + (*displayDump)->getData(addr, &oldValue, dataTypeSizes[searchType]); + newMemDump->getData(addr, &newValue, dataTypeSizes[searchType]); + + if (addr % 500 == 0) { + setLedState(ledOn); + ledOn = !ledOn; + } + + switch(searchMode) { + case SEARCH_MODE_SAME: + if (newValue._u64 == oldValue._u64) + addrDump->addData((u8*)&addr, sizeof(u64)); + break; + case SEARCH_MODE_DIFF: + if (newValue._u64 != oldValue._u64) + addrDump->addData((u8*)&addr, sizeof(u64)); + break; + case SEARCH_MODE_INC: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (newValue._s64 > oldValue._s64) + (*displayDump)->addData((u8*)&addr, sizeof(u64)); + } else { + if (newValue._u64 > oldValue._u64) + (*displayDump)->addData((u8*)&addr, sizeof(u64)); + } + break; + case SEARCH_MODE_DEC: + if (searchType & (SEARCH_TYPE_SIGNED_8BIT | SEARCH_TYPE_SIGNED_16BIT | SEARCH_TYPE_SIGNED_32BIT | SEARCH_TYPE_SIGNED_64BIT | SEARCH_TYPE_FLOAT_32BIT | SEARCH_TYPE_FLOAT_64BIT)) { + if (newValue._s64 < oldValue._s64) + (*displayDump)->addData((u8*)&addr, sizeof(u64)); + } else { + if (newValue._u64 < oldValue._u64) + (*displayDump)->addData((u8*)&addr, sizeof(u64)); + } + break; + } + + } + + setLedState(false); +} + +void GuiCheats::searchMemoryValuesTertiary(Debugger *debugger, searchType_t searchType, searchMode_t searchMode, searchRegion_t searchRegion, MemoryDump **displayDump, std::vector memInfos) { + MemoryDump *newMemDump = new MemoryDump(EDIZON_DIR "/memdump2.dat", DumpType::DATA, true); + MemoryDump *addrDump = new MemoryDump(EDIZON_DIR "/memdump3.dat", DumpType::ADDR, true); + u64 dumpOffset = 0; + + for (MemoryInfo meminfo : memInfos) { + if (searchRegion == SEARCH_REGION_HEAP && meminfo.type != MemType_Heap) + continue; + else if (searchRegion == SEARCH_REGION_MAIN && + (meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_HEAP_AND_MAIN && + (meminfo.type != MemType_Heap && meminfo.type != MemType_CodeWritable && meminfo.type != MemType_CodeMutable)) + continue; + else if (searchRegion == SEARCH_REGION_RAM && (meminfo.perm & Perm_Rw) != Perm_Rw) + continue; + + u64 offset = 0; + u64 bufferSize = 0x40000; + u8 *buffer = new u8[bufferSize]; + while (offset < meminfo.size) { + + if (meminfo.size - offset < bufferSize) + bufferSize = meminfo.size - offset; + + debugger->readMemory(buffer, bufferSize, meminfo.addr + offset); + (*displayDump)->addData(buffer, bufferSize); + + offset += bufferSize; + } + + delete[] buffer; + } +} + +/** + * Primary: + * Initial full memory dump regardless of type + * Differentiate between different regions and types + * + * Secondary: + * Second full memory dump regardless of type + * Differentiate between regions and types. (both fix now) + * + * Compare both memory dumps based on type and mode + * Store match addresses into additional file + * Matches should be stored as [MEMADDR][DUMPADDR] for fast comparing later on + * + * Tertiary (Loop infinitely): + * Iterate over match addrs file + * Compare value in memory at [MEMADDR] with value in second memory dump at [DUMPADDR] + * Store match addresses into file (displayDump) + * Dump all values from changed addresses into a file + * Matches should be stored as [MEMADDR][DUMPADDR] for fast comparing later on + */ + +static void _moveLonelyCheats(u8 *buildID, u64 titleID) { + std::stringstream lonelyCheatPath; + std::stringstream realCheatPath; + + std::stringstream buildIDStr; + + for (u8 i = 0; i < 8; i++) + buildIDStr << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)buildID[i]; + + lonelyCheatPath << EDIZON_DIR "/cheats/" << buildIDStr.str() << ".txt"; + + if (access(lonelyCheatPath.str().c_str(), F_OK) == 0) { + realCheatPath << "/atmosphere/titles/" << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << titleID; + mkdir(realCheatPath.str().c_str(), 0777); + realCheatPath << "/cheats/"; + mkdir(realCheatPath.str().c_str(), 0777); + + realCheatPath << buildIDStr.str() << ".txt"; + + rename(lonelyCheatPath.str().c_str(), realCheatPath.str().c_str()); + + (new MessageBox("A new cheat has been added for this title. \n Please restart the game to start using it.", MessageBox::OKAY))->show(); + } +} + +static bool _wrongCheatsPresent(u8 *buildID, u64 titleID) { + std::stringstream ss; + + ss << "/atmosphere/titles/" << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(u64) * 2) << titleID << "/cheats/"; + + if (!std::filesystem::exists(ss.str())) + return false; + + bool cheatsFolderEmpty = std::filesystem::is_empty(ss.str()); + + for (u8 i = 0; i < 8; i++) + ss << std::nouppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)buildID[i]; + ss << ".txt"; + + bool realCheatDoesExist = std::filesystem::exists(ss.str()); + + return !(cheatsFolderEmpty || realCheatDoesExist); +} diff --git a/source/guis/gui_editor.cpp b/source/guis/gui_editor.cpp index 50079b82..dbbf0399 100644 --- a/source/guis/gui_editor.cpp +++ b/source/guis/gui_editor.cpp @@ -1,767 +1,767 @@ -#include "guis/gui_editor.hpp" - -#include "helpers/title.hpp" -#include "helpers/save.hpp" - -#include "helpers/editor_config_parser.hpp" -#include "scripting/interpreter.hpp" -#include "scripting/lua_interpreter.hpp" -#include "scripting/python_interpreter.hpp" - -#include "upload_manager.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define COLOR_THRESHOLD 35 - -GuiEditor::GuiEditor() : Gui() { - m_titleIcon.reserve(128 * 128 * 3); - std::vector smallTitleIcon(32 * 32 * 3); - std::map colors; - - m_dominantColor = Gui::makeColor(0xA0, 0xA0, 0xA0, 0xFF); - - if (Title::g_currTitle->getTitleID() == Title::g_activeTitle) { - Title *nextTitle = nullptr; - bool isCurrTitle = false; - - for (auto title : Title::g_titles) { - if (isCurrTitle) { - nextTitle = title.second; - break; - } - isCurrTitle = title.second == Title::g_currTitle; - } - - if (nextTitle == nullptr) - nextTitle = Title::g_titles.begin()->second; - - Title::g_currTitle = nextTitle; - Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; - Gui::g_nextGui = GUI_EDITOR; - } - - - Gui::resizeImage(Title::g_currTitle->getTitleIcon(), &m_titleIcon[0], 256, 256, 128, 128); - Gui::resizeImage(Title::g_currTitle->getTitleIcon(), &smallTitleIcon[0], 256, 256, 32, 32); - - for (u16 i = 0; i < 32 * 32 * 3; i += 3) { - u32 currColor = smallTitleIcon[i + 0] << 16 | smallTitleIcon[i + 1] << 8 | smallTitleIcon[i + 2]; - colors[currColor]++; - } - - u32 dominantUseCnt = 0; - for (auto [color, count] : colors) { - if (count > dominantUseCnt) { - color_t colorCandidate = Gui::makeColor((color & 0xFF0000) >> 16, (color & 0x00FF00) >> 8, (color & 0x0000FF), 0xFF); - - if(!(abs(static_cast(colorCandidate.r) - colorCandidate.g) > COLOR_THRESHOLD || abs(static_cast(colorCandidate.r) - colorCandidate.b) > COLOR_THRESHOLD)) - continue; - - dominantUseCnt = count; - m_dominantColor = colorCandidate; - } - } - - m_textColor = (m_dominantColor.r > 0x80 && m_dominantColor.g > 0x80 && m_dominantColor.b > 0x80) ? COLOR_BLACK : COLOR_WHITE; - - Widget::g_widgetPage = 0; - Widget::g_selectedWidgetIndex = 0; - Widget::g_selectedCategory = ""; - - std::stringstream path; - path << CONFIG_ROOT << std::setfill('0') << std::setw(sizeof(u64) * 2) << std::uppercase << std::hex << Title::g_currTitle->getTitleID() << ".json"; - m_configFileResult = EditorConfigParser::loadConfigFile(Title::g_currTitle->getTitleID(), path.str(), &m_interpreter); -} - -GuiEditor::~GuiEditor() { - if (GuiEditor::g_currSaveFileName != "") { - for (auto const& [category, widgets] : m_widgets) - for(auto widget : widgets) - delete widget.widget; - - delete m_interpreter; - } - - GuiEditor::g_currSaveFile.clear(); - GuiEditor::g_currSaveFileName = ""; - EditorConfigParser::g_currConfigAuthor = ""; - Widget::g_selectedCategory = ""; - - m_backupTitles.clear(); - m_backupPaths.clear(); - m_backupFolderNames.clear(); - - m_saveFiles.clear(); -} - -void GuiEditor::update() { - Gui::update(); -} - -void GuiEditor::draw() { - Gui::beginDraw(); - - std::stringstream ssTitleId; - ssTitleId << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); - - Widget::drawWidgets(this, m_widgets, Widget::g_widgetPage * WIDGETS_PER_PAGE, (Widget::g_widgetPage + 1) * WIDGETS_PER_PAGE); - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, 128, m_dominantColor); - Gui::drawImage(0, 0, 128, 128, &m_titleIcon[0], IMAGE_MODE_RGB24); - Gui::drawImage(Gui::g_framebuffer_width - 128, 0, 128, 128, Account::g_currAccount->getProfileImage(), IMAGE_MODE_RGB24); - Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 128); - - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), 10, m_textColor, Title::g_currTitle->getTitleName().c_str(), ALIGNED_CENTER); - - Gui::drawRectangle(0, Gui::g_framebuffer_height - 73, Gui::g_framebuffer_width, 73, currTheme.backgroundColor); - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); - - if (GuiEditor::g_currSaveFileName == "") { - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 50, m_textColor, Title::g_currTitle->getTitleAuthor().c_str(), ALIGNED_CENTER); - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 80, m_textColor, ssTitleId.str().c_str(), ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E6 Next game \uE0E7 Next user \uE0E2 Backup \uE0E3 Restore \uE0E1 Back", ALIGNED_RIGHT); - switch (m_configFileResult) { - case 0: - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "Press \uE0F0 to load and edit your save file.", ALIGNED_CENTER); - break; - case 1: - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No config for this game was found. Editing is disabled.", ALIGNED_CENTER); - break; - case 2: - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "Syntax error in config file! Editing is disabled.", ALIGNED_CENTER); - break; - case 3: - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "The config isn't compatible with your game's version. Editing is disabled.", ALIGNED_CENTER); - break; - case 4: - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "The config redirected more than 5 times. Editing is disabled.", ALIGNED_CENTER); - break; - } - - } else { - std::stringstream ssMultiplier; - ssMultiplier << "\uE074 : x"; - ssMultiplier << Widget::g_stepSizeMultiplier; - - if (EditorConfigParser::g_currConfigAuthor != "") - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 80, m_textColor, std::string("Config created by " + EditorConfigParser::g_currConfigAuthor).c_str(), ALIGNED_CENTER); - - Gui::drawTextAligned(font20, 50, Gui::g_framebuffer_height - 50, currTheme.textColor, ssMultiplier.str().c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE105 Increase multiplier \uE0E2 Apply changes \uE0E1 Cancel \uE0E0 OK", ALIGNED_RIGHT); - } - - if (m_widgets[Widget::g_selectedCategory].size() > WIDGETS_PER_PAGE) { - for (u8 page = 0; page < Widget::g_widgetPageCnt[Widget::g_selectedCategory]; page++) { - Gui::drawRectangle((Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + page * 30 , 608, 20, 20, currTheme.separatorColor); - - if (page == Widget::g_widgetPage) - Gui::drawRectangled((Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + page * 30 + 4, 612, 12, 12, currTheme.highlightColor); - } - - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 - 30, 602, currTheme.textColor, "\uE0A4", ALIGNED_CENTER); - Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2) + Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + 23, 602, currTheme.textColor, "\uE0A5", ALIGNED_CENTER); - - } - - Gui::endDraw(); -} - -void GuiEditor::updateBackupList() { - DIR *dir_batch; - DIR *dir_users; - DIR *dir_titles; - - struct dirent *ent_timestamp; - struct dirent *ent_user; - - std::vector backups; - - std::string metadataUsername; - - m_backupTitles.clear(); - m_backupPaths.clear(); - m_backupFolderNames.clear(); - - std::stringstream path; - - path << EDIZON_DIR "/restore"; - if ((dir_titles = opendir(path.str().c_str())) != nullptr) { - while ((ent_timestamp = readdir(dir_titles)) != nullptr) { - if (ent_timestamp->d_type != DT_DIR) continue; - - metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/" + std::string(ent_timestamp->d_name) + "/edizon_save_metadata.json"); - if (metadataUsername.empty()) - metadataUsername = "By an unknown user [/restore]"; - else - metadataUsername = "By " + metadataUsername + " [/restore]"; - - backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); - backups.push_back(path.str() + "/" + std::string(ent_timestamp->d_name)); - backups.push_back(std::string(ent_timestamp->d_name)); - } - closedir(dir_titles); - } - - //Read batch saves - if ((dir_batch = opendir(EDIZON_DIR "/batch_saves")) != nullptr) { - while ((ent_timestamp = readdir(dir_batch)) != nullptr) { - path.str(""); - path << EDIZON_DIR "/batch_saves/" << std::string(ent_timestamp->d_name); - if ((dir_users = opendir(path.str().c_str())) != nullptr) { - while ((ent_user = readdir(dir_users)) != nullptr) { - if (ent_user->d_type != DT_DIR) continue; - - path.str(""); - path << EDIZON_DIR "/batch_saves/" << std::string(ent_timestamp->d_name) << "/" << std::string(ent_user->d_name) << "/" << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); - if ((dir_titles = opendir(path.str().c_str())) != nullptr) { - metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/edizon_save_metadata.json"); - - if (metadataUsername.empty()) - metadataUsername = "By an unknown user [Batch]"; - else - metadataUsername = "By " + metadataUsername + " [Batch]"; - - backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); - backups.push_back(path.str()); - backups.push_back(std::string(ent_timestamp->d_name)); - - closedir(dir_titles); - } - } - closedir(dir_users); - } - } - closedir(dir_batch); - } - - path.str(""); - - //Read root saves - path << EDIZON_DIR "/saves/" << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); - if ((dir_titles = opendir(path.str().c_str())) != nullptr) { - while ((ent_timestamp = readdir(dir_titles)) != nullptr) { - if (ent_timestamp->d_type != DT_DIR) continue; - - metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/" + std::string(ent_timestamp->d_name) + "/edizon_save_metadata.json"); - if (metadataUsername.empty()) - metadataUsername = "By an unknown user"; - else - metadataUsername = "By " + metadataUsername; - - backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); - backups.push_back(path.str() + "/" + std::string(ent_timestamp->d_name)); - backups.push_back(std::string(ent_timestamp->d_name)); - } - closedir(dir_titles); - } - - - for (auto iter = backups.begin(); iter != backups.end();) { - m_backupTitles.push_back(*iter++); - m_backupPaths.push_back(*iter++); - m_backupFolderNames.push_back(*iter++); - } - - std::reverse(m_backupTitles.begin(), m_backupTitles.end()); - std::reverse(m_backupPaths.begin(), m_backupPaths.end()); - std::reverse(m_backupFolderNames.begin(), m_backupFolderNames.end()); - -} - -std::string GuiEditor::readMetaDataUsername(std::string path) { - json metadata_json; - - std::ifstream metadata_file (path); - - if (metadata_file.is_open()) { - metadata_file >> metadata_json; - metadata_file.close(); - try { - return metadata_json["user_name"].get(); - } catch (json::parse_error& e) { } - } - - return ""; -} - -void GuiEditor::updateSaveFileList(std::vector saveFilePath, std::string files, u8 configIndex) { - DIR *dir; - struct dirent *ent; - FsFileSystem fs; - - std::vector pathsOld; - std::vector paths; - - if (mountSaveByTitleAccountIDs(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), fs)) - return; - - if (saveFilePath[0] != "") { - dir = opendir("save:/"); - - while ((ent = readdir(dir)) != nullptr) { - if (std::regex_match(std::string(ent->d_name), std::regex(saveFilePath[0]))) { - pathsOld.push_back(std::string(ent->d_name) + "/"); - } - } - - closedir(dir); - - for (u16 i = 1; i < saveFilePath.size(); i++) { - for (auto path : pathsOld) { - dir = opendir(path.c_str()); - while ((ent = readdir(dir)) != nullptr) { - if (std::regex_match(std::string(ent->d_name), std::regex(saveFilePath[i]))) { - std::string newPath = path; - newPath += "/"; - newPath += ent->d_name; - paths.push_back(newPath); - } - } - - closedir(dir); - } - - pathsOld = paths; - paths.clear(); - } - } else pathsOld.push_back(""); - - for (auto path : pathsOld) { - std::string finalSaveFilePath = std::string("save:/") + path; - if ((dir = opendir(finalSaveFilePath.c_str())) != nullptr) { - std::regex validSaveFileNames(files); - - while ((ent = readdir(dir)) != nullptr) { - if (std::regex_match(ent->d_name, validSaveFileNames)) - m_saveFiles.push_back({ path + ent->d_name, configIndex }); - } - closedir(dir); - } - } - - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - -} - -void uploadBackup(std::string path, std::string fileName) { - UploadManager um; - static std::stringstream hashStr; - - (new MessageBox("Uploading savefile...\n \nPress \uE0E1 to cancel.", MessageBox::NONE))->show(); - requestDraw(); - - char serial[0x19]; - u8 serialHash[0x20]; - setsysGetSerialNumber(serial); - - - Sha256Context shaCtx; - sha256ContextCreate(&shaCtx); - sha256ContextUpdate(&shaCtx, (u8 *)serial, 0x19); - sha256ContextGetHash(&shaCtx, serialHash); - - hashStr.str(""); - - for (u8 i = 0; i < 0x20; i++) { - hashStr << std::hex << (serialHash[i] & 0x0F); - hashStr << std::hex << (serialHash[i] >> 4); - } - - static std::string retCode; - retCode = um.upload(path, fileName, Title::g_currTitle, hashStr.str()); - retCode = retCode.substr(0, retCode.find("\n") - 1); - - if (retCode.length() == 6) { - (new MessageBox("", MessageBox::OKAY))->setCustomDraw([&](Gui *gui, s16 x, s16 y){ - u32 w, h; - gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "Upload finished!\n \n Visit edizon.werwolv.net and enter this code\n to get your link!", ALIGNED_CENTER); - - gui->getTextDimensions(font24, retCode.c_str(), &w, &h); - - gui->drawRectangle(x + (780 / 2) - (w / 2) - 20, y + 210, w + 40, h + 20, currTheme.tooltipColor); - gui->drawTextAligned(font24, x + (780 / 2), y + 210, currTheme.textColor, retCode.c_str(), ALIGNED_CENTER); - })->show(); - } - else - (new MessageBox("Upload failed!\n \n" + retCode, MessageBox::OKAY))->show(); -} - -void GuiEditor::onInput(u32 kdown) { -if (GuiEditor::g_currSaveFileName == "") { /* No savefile loaded */ - - if (kdown & KEY_MINUS) { - if (m_configFileResult != 0) return; - m_saveFiles.clear(); - - for (u8 configIndex = 0; configIndex < EditorConfigParser::getConfigFile().size(); configIndex++) - updateSaveFileList(EditorConfigParser::getConfigFile()[configIndex]["saveFilePaths"], EditorConfigParser::getConfigFile()[configIndex]["files"], configIndex); - - static std::vector saveFileNames; - - saveFileNames.clear(); - - for (auto saveFile : m_saveFiles) - saveFileNames.push_back(saveFile.fileName); - - (new ListSelector("Edit save file", "\uE0E0 Select \uE0E1 Back", saveFileNames))->setInputAction([&](u32 k, u16 selectedItem) { - if (k & KEY_A) { - if (m_saveFiles.size() != 0) { - size_t length; - Widget::g_selectedWidgetIndex = 0; - Widget::g_selectedCategory = ""; - Widget::g_selectedRow = CATEGORIES; - Widget::g_categoryYOffset = 0; - - (new MessageBox("Starting up editor...", MessageBox::NONE))->show(); - requestDraw(); - Gui::g_currMessageBox->hide(); - - GuiEditor::g_currSaveFileName = m_saveFiles[Gui::g_currListSelector->selectedItem].fileName.c_str(); - - if (loadSaveFile(&GuiEditor::g_currSaveFile, &length, Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), GuiEditor::g_currSaveFileName.c_str()) == 0) { - m_interpreter->setSaveFileBuffer(&g_currSaveFile[0], length, EditorConfigParser::getOptionalValue(EditorConfigParser::getConfigFile(), "encoding", "ascii")); - EditorConfigParser::createWidgets(m_widgets, *m_interpreter, this->m_saveFiles[selectedItem].configIndex); - - if (EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["startupMessage"] != nullptr) - (new MessageBox(EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["startupMessage"], MessageBox::OKAY))->show(); - - if(!m_interpreter->initialize(EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["filetype"])) { - m_interpreter->deinitialize(); - Gui::g_currMessageBox->hide(); - - GuiEditor::g_currSaveFile.clear(); - GuiEditor::g_currSaveFileName = ""; - - for (auto const& [category, widgets] : m_widgets) - for(auto widget : widgets) - delete widget.widget; - - m_widgets.clear(); - Widget::g_categories.clear(); - (new Snackbar("Failed to start script interpreter! Syntax error or script not found."))->show(); - - Gui::g_currListSelector->hide(); - return; - } - } - else { - (new Snackbar("Failed to load save file! Is it empty?"))->show(); - GuiEditor::g_currSaveFile.clear(); - GuiEditor::g_currSaveFileName = ""; - - for (auto const& [category, widgets] : m_widgets) - for(auto widget : widgets) - delete widget.widget; - - m_widgets.clear(); - } - Gui::g_currListSelector->hide(); - } - } - })->show(); - } - - if (kdown & KEY_B) { - Gui::g_nextGui = GUI_MAIN; - } - - if (kdown & KEY_X) { - s16 res; - - time_t t = time(nullptr); - static char backupName[65]; - std::stringstream initialText; - initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); - if(!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) - return; - - (new MessageBox("Extracting save file.\n \nThis may take a while...", MessageBox::NONE))->show(); - requestDraw(); - - if(!(res = backupSave(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), false, backupName))) { - (new MessageBox("Successfully created backup!\n \n Would you like to upload it to anonfile.com?", MessageBox::YES_NO))->setSelectionAction([&](u8 selection) { - if (selection) { - std::stringstream backupPath; - backupPath << EDIZON_DIR "/saves/" << std::uppercase << std::setfill('0') - << std::setw(sizeof(Title::g_currTitle->getTitleID())*2) - << std::hex << Title::g_currTitle->getTitleID() - << "/" << std::string(backupName); - - uploadBackup(backupPath.str(), backupName); - } else Gui::g_currMessageBox->hide(); - })->show(); - - } - else { - Gui::g_currMessageBox->hide(); - switch(res) { - case 1: (new Snackbar("Failed to mount save file!"))->show(); break; - case 2: (new Snackbar("A backup with this name already exists!"))->show(); break; - case 3: (new Snackbar("Failed to create backup!"))->show(); break; - } - } - } - - if (kdown & KEY_Y) { - updateBackupList(); - - (new ListSelector("Restore Backup", "\uE0F0 Upload \uE0E0 Restore \uE0E2 Delete \uE0E1 Back", m_backupTitles))->setInputAction([&](u32 k, u16 selectedItem){ - if (k & KEY_A) { - if (m_backupTitles.size() != 0) { - (new MessageBox("Are you sure you want to inject this backup?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { - if (selection) { - s16 res; - - if(!(res = restoreSave(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), m_backupPaths[Gui::g_currListSelector->selectedItem].c_str()))) - (new Snackbar("Successfully restored backup!"))->show(); - else (new Snackbar("An error occured while restoring the backup! Error " + std::to_string(res)))->show(); - - Gui::g_currListSelector->hide(); - Gui::g_currMessageBox->hide(); - } else Gui::g_currMessageBox->hide(); - })->show(); - } - } - - if (k & KEY_X) { - std::stringstream path; - deleteDirRecursively(m_backupPaths[Gui::g_currListSelector->selectedItem].c_str(), false); - updateBackupList(); - - if (Gui::g_currListSelector->selectedItem == m_backupTitles.size() && Gui::g_currListSelector->selectedItem > 0) - Gui::g_currListSelector->selectedItem--; - } - - if (k & KEY_MINUS) { - uploadBackup(m_backupPaths[Gui::g_currListSelector->selectedItem], m_backupFolderNames[Gui::g_currListSelector->selectedItem]); - - Gui::g_currListSelector->hide(); - } - })->show(); - } - - if (kdown & KEY_ZL) { - Title *nextTitle = nullptr; - bool isCurrTitle = false; - - for (auto title : Title::g_titles) { - if (isCurrTitle) { - nextTitle = title.second; - - break; - } - - isCurrTitle = title.second == Title::g_currTitle; - } - - if (nextTitle == nullptr) - nextTitle = Title::g_titles.begin()->second; - - Title::g_currTitle = nextTitle; - Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; - Gui::g_nextGui = GUI_EDITOR; - } - - if (kdown & KEY_ZR) { - Account *nextAccount = nullptr; - bool isCurrAccount = false; - - for (auto userID : Title::g_currTitle->getUserIDs()) { - if (isCurrAccount) { - nextAccount = Account::g_accounts[userID]; - break; - } - isCurrAccount = userID == Account::g_currAccount->getUserID(); - } - - if (nextAccount == nullptr) - nextAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; - - if (Title::g_currTitle->getUserIDs().size() != 1) { - Account::g_currAccount = nextAccount; - Gui::g_nextGui = GUI_EDITOR; - } else nextAccount = nullptr; - } - } /* Savefile loaded */ - else { - if (Widget::g_selectedRow == WIDGETS) { /* Widgets row */ - if (kdown & KEY_L) { - if (Widget::g_widgetPage > 0) - Widget::g_widgetPage--; - Widget::g_selectedWidgetIndex = WIDGETS_PER_PAGE * Widget::g_widgetPage; - } - - if (kdown & KEY_R) { - if (Widget::g_widgetPage < Widget::g_widgetPageCnt[Widget::g_selectedCategory] - 1) - Widget::g_widgetPage++; - Widget::g_selectedWidgetIndex = WIDGETS_PER_PAGE * Widget::g_widgetPage ; - } - - if (kdown & KEY_B || kdown & KEY_LSTICK_LEFT || kdown & KEY_RSTICK_LEFT) { - Widget::g_selectedRow = CATEGORIES; - Widget::g_selectedWidgetIndex = std::distance(Widget::g_categories.begin(), std::find(Widget::g_categories.begin(), Widget::g_categories.end(), Widget::g_selectedCategory)); - } - - if (kdown & KEY_LSTICK_UP || kdown & KEY_RSTICK_UP) { - if (Widget::g_selectedWidgetIndex > 0) - Widget::g_selectedWidgetIndex--; - Widget::g_widgetPage = floor(Widget::g_selectedWidgetIndex / WIDGETS_PER_PAGE); - } - - if (kdown & KEY_LSTICK_DOWN || kdown & KEY_RSTICK_DOWN) { - if (Widget::g_selectedWidgetIndex < m_widgets[Widget::g_selectedCategory].size() - 1) - Widget::g_selectedWidgetIndex++; - Widget::g_widgetPage = floor(Widget::g_selectedWidgetIndex / WIDGETS_PER_PAGE); - } - - } else { /* Categories row */ - if (kdown & KEY_B) { - (new MessageBox("Are you sure you want to discard your changes?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { - if (selection) { - m_interpreter->deinitialize(); - - GuiEditor::g_currSaveFile.clear(); - GuiEditor::g_currSaveFileName = ""; - - for (auto const& [category, widgets] : m_widgets) - for(auto widget : widgets) - delete widget.widget; - - m_widgets.clear(); - Widget::g_categories.clear(); - Gui::g_currMessageBox->hide(); - } else Gui::g_currMessageBox->hide(); - })->show(); - - return; - } - - if (kdown & KEY_LSTICK_UP || kdown & KEY_RSTICK_UP) { - if (Widget::g_selectedWidgetIndex > 0) { - Widget::g_selectedWidgetIndex--; - - if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 7 && Widget::g_categoryYOffset != 0) - Widget::g_categoryYOffset--; - } - Widget::g_selectedCategory = Widget::g_categories[Widget::g_selectedWidgetIndex]; - Widget::g_widgetPage = 0; - } - - if (kdown & KEY_LSTICK_DOWN || kdown & KEY_RSTICK_DOWN) { - if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 1) { - Widget::g_selectedWidgetIndex++; - - if (Widget::g_selectedWidgetIndex > 6 && Widget::g_categoryYOffset < Widget::g_categories.size() - 8) - Widget::g_categoryYOffset++; - } - Widget::g_selectedCategory = Widget::g_categories[Widget::g_selectedWidgetIndex]; - Widget::g_widgetPage = 0; - } - } - /* Categories and widgets row */ - if (kdown & KEY_X) { - (new MessageBox(EditorConfigParser::g_betaTitles[Title::g_currTitle->getTitleID()] ? "Do you want to apply these changes? \n Make sure you have a working backup of your \n save data as this config is still in beta!" :"Do you want to apply these changes?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { - if (selection) { - std::vector buffer; - - m_interpreter->getModifiedSaveFile(buffer); - - if(buffer.empty()) - (new Snackbar("Injection of modified values failed!"))->show(); - else { - if(!storeSaveFile(&buffer[0], buffer.size(), Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), GuiEditor::g_currSaveFileName.c_str())) - (new Snackbar("Successfully injected modified values!"))->show(); - else - (new Snackbar("Injection of modified values failed!"))->show(); - } - - m_interpreter->deinitialize(); - GuiEditor::g_currSaveFile.clear(); - GuiEditor::g_currSaveFileName = ""; - - Widget::g_widgetPage = 0; - - for (auto const& [category, widgets] : m_widgets) - for(auto widget : widgets) - delete widget.widget; - - Widget::g_categories.clear(); - m_widgets.clear(); - Gui::g_currMessageBox->hide(); - } else Gui::g_currMessageBox->hide(); - })->show(); - - return; - } - - Widget::handleInput(kdown, m_widgets); - } -} - -void GuiEditor::onTouch(touchPosition &touch) { - if (GuiEditor::g_currSaveFileName == "") { - if (touch.px < 128 && touch.py < 128) { - Title *nextTitle = nullptr; - bool isCurrTitle = false; - - for (auto title : Title::g_titles) { - if (isCurrTitle) { - nextTitle = title.second; - break; - } - - isCurrTitle = title.second == Title::g_currTitle; - } - - if (nextTitle == nullptr) - nextTitle = Title::g_titles.begin()->second; - - Title::g_currTitle = nextTitle; - Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; - Gui::g_nextGui = GUI_EDITOR; - } - - if (touch.px > Gui::g_framebuffer_width - 128 && touch.py < 128) { - Account *nextAccount = nullptr; - bool isCurrAccount = false; - - for (auto userID : Title::g_currTitle->getUserIDs()) { - if (isCurrAccount) { - nextAccount = Account::g_accounts[userID]; - break; - } - isCurrAccount = userID == Account::g_currAccount->getUserID(); - } - - if (nextAccount == nullptr) - nextAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; - - if (Title::g_currTitle->getUserIDs().size() != 1) { - Account::g_currAccount = nextAccount; - Gui::g_nextGui = GUI_EDITOR; - } else nextAccount = nullptr; - } - } else { - //s8 widgetTouchPos = floor((touch.py - 150) / (static_cast(WIDGET_HEIGHT) + WIDGET_SEPARATOR)) + WIDGETS_PER_PAGE * Widget::g_widgetPage; - Widget::handleTouch(touch, m_widgets); - } -} - -void GuiEditor::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} +#include "guis/gui_editor.hpp" + +#include "helpers/title.hpp" +#include "helpers/save.hpp" + +#include "helpers/editor_config_parser.hpp" +#include "scripting/interpreter.hpp" +#include "scripting/lua_interpreter.hpp" +#include "scripting/python_interpreter.hpp" + +#include "upload_manager.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COLOR_THRESHOLD 35 + +GuiEditor::GuiEditor() : Gui() { + m_titleIcon.reserve(128 * 128 * 3); + std::vector smallTitleIcon(32 * 32 * 3); + std::map colors; + + m_dominantColor = Gui::makeColor(0xA0, 0xA0, 0xA0, 0xFF); + + if (Title::g_currTitle->getTitleID() == Title::g_activeTitle) { + Title *nextTitle = nullptr; + bool isCurrTitle = false; + + for (auto title : Title::g_titles) { + if (isCurrTitle) { + nextTitle = title.second; + break; + } + isCurrTitle = title.second == Title::g_currTitle; + } + + if (nextTitle == nullptr) + nextTitle = Title::g_titles.begin()->second; + + Title::g_currTitle = nextTitle; + Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; + Gui::g_nextGui = GUI_EDITOR; + } + + + Gui::resizeImage(Title::g_currTitle->getTitleIcon(), &m_titleIcon[0], 256, 256, 128, 128); + Gui::resizeImage(Title::g_currTitle->getTitleIcon(), &smallTitleIcon[0], 256, 256, 32, 32); + + for (u16 i = 0; i < 32 * 32 * 3; i += 3) { + u32 currColor = smallTitleIcon[i + 0] << 16 | smallTitleIcon[i + 1] << 8 | smallTitleIcon[i + 2]; + colors[currColor]++; + } + + u32 dominantUseCnt = 0; + for (auto [color, count] : colors) { + if (count > dominantUseCnt) { + color_t colorCandidate = Gui::makeColor((color & 0xFF0000) >> 16, (color & 0x00FF00) >> 8, (color & 0x0000FF), 0xFF); + + if(!(abs(static_cast(colorCandidate.r) - colorCandidate.g) > COLOR_THRESHOLD || abs(static_cast(colorCandidate.r) - colorCandidate.b) > COLOR_THRESHOLD)) + continue; + + dominantUseCnt = count; + m_dominantColor = colorCandidate; + } + } + + m_textColor = (m_dominantColor.r > 0x80 && m_dominantColor.g > 0x80 && m_dominantColor.b > 0x80) ? COLOR_BLACK : COLOR_WHITE; + + Widget::g_widgetPage = 0; + Widget::g_selectedWidgetIndex = 0; + Widget::g_selectedCategory = ""; + + std::stringstream path; + path << CONFIG_ROOT << std::setfill('0') << std::setw(sizeof(u64) * 2) << std::uppercase << std::hex << Title::g_currTitle->getTitleID() << ".json"; + m_configFileResult = EditorConfigParser::loadConfigFile(Title::g_currTitle->getTitleID(), path.str(), &m_interpreter); +} + +GuiEditor::~GuiEditor() { + if (GuiEditor::g_currSaveFileName != "") { + for (auto const& [category, widgets] : m_widgets) + for(auto widget : widgets) + delete widget.widget; + + delete m_interpreter; + } + + GuiEditor::g_currSaveFile.clear(); + GuiEditor::g_currSaveFileName = ""; + EditorConfigParser::g_currConfigAuthor = ""; + Widget::g_selectedCategory = ""; + + m_backupTitles.clear(); + m_backupPaths.clear(); + m_backupFolderNames.clear(); + + m_saveFiles.clear(); +} + +void GuiEditor::update() { + Gui::update(); +} + +void GuiEditor::draw() { + Gui::beginDraw(); + + std::stringstream ssTitleId; + ssTitleId << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); + + Widget::drawWidgets(this, m_widgets, Widget::g_widgetPage * WIDGETS_PER_PAGE, (Widget::g_widgetPage + 1) * WIDGETS_PER_PAGE); + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, 128, m_dominantColor); + Gui::drawImage(0, 0, 128, 128, &m_titleIcon[0], IMAGE_MODE_RGB24); + Gui::drawImage(Gui::g_framebuffer_width - 128, 0, 128, 128, Account::g_currAccount->getProfileImage(), IMAGE_MODE_RGB24); + Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 128); + + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), 10, m_textColor, Title::g_currTitle->getTitleName().c_str(), ALIGNED_CENTER); + + Gui::drawRectangle(0, Gui::g_framebuffer_height - 73, Gui::g_framebuffer_width, 73, currTheme.backgroundColor); + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); + + if (GuiEditor::g_currSaveFileName == "") { + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 50, m_textColor, Title::g_currTitle->getTitleAuthor().c_str(), ALIGNED_CENTER); + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 80, m_textColor, ssTitleId.str().c_str(), ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE0E6 Next game \uE0E7 Next user \uE0E2 Backup \uE0E3 Restore \uE0E1 Back", ALIGNED_RIGHT); + switch (m_configFileResult) { + case 0: + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "Press \uE0F0 to load and edit your save file.", ALIGNED_CENTER); + break; + case 1: + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No config for this game was found. Editing is disabled.", ALIGNED_CENTER); + break; + case 2: + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "Syntax error in config file! Editing is disabled.", ALIGNED_CENTER); + break; + case 3: + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "The config isn't compatible with your game's version. Editing is disabled.", ALIGNED_CENTER); + break; + case 4: + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "The config redirected more than 5 times. Editing is disabled.", ALIGNED_CENTER); + break; + } + + } else { + std::stringstream ssMultiplier; + ssMultiplier << "\uE074 : x"; + ssMultiplier << Widget::g_stepSizeMultiplier; + + if (EditorConfigParser::g_currConfigAuthor != "") + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2), 80, m_textColor, std::string("Config created by " + EditorConfigParser::g_currConfigAuthor).c_str(), ALIGNED_CENTER); + + Gui::drawTextAligned(font20, 50, Gui::g_framebuffer_height - 50, currTheme.textColor, ssMultiplier.str().c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, "\uE105 Increase multiplier \uE0E2 Apply changes \uE0E1 Cancel \uE0E0 OK", ALIGNED_RIGHT); + } + + if (m_widgets[Widget::g_selectedCategory].size() > WIDGETS_PER_PAGE) { + for (u8 page = 0; page < Widget::g_widgetPageCnt[Widget::g_selectedCategory]; page++) { + Gui::drawRectangle((Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + page * 30 , 608, 20, 20, currTheme.separatorColor); + + if (page == Widget::g_widgetPage) + Gui::drawRectangled((Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + page * 30 + 4, 612, 12, 12, currTheme.highlightColor); + } + + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2) - Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 - 30, 602, currTheme.textColor, "\uE0A4", ALIGNED_CENTER); + Gui::drawTextAligned(font20, (Gui::g_framebuffer_width / 2) + Widget::g_widgetPageCnt[Widget::g_selectedCategory] * 15 + 23, 602, currTheme.textColor, "\uE0A5", ALIGNED_CENTER); + + } + + Gui::endDraw(); +} + +void GuiEditor::updateBackupList() { + DIR *dir_batch; + DIR *dir_users; + DIR *dir_titles; + + struct dirent *ent_timestamp; + struct dirent *ent_user; + + std::vector backups; + + std::string metadataUsername; + + m_backupTitles.clear(); + m_backupPaths.clear(); + m_backupFolderNames.clear(); + + std::stringstream path; + + path << EDIZON_DIR "/restore"; + if ((dir_titles = opendir(path.str().c_str())) != nullptr) { + while ((ent_timestamp = readdir(dir_titles)) != nullptr) { + if (ent_timestamp->d_type != DT_DIR) continue; + + metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/" + std::string(ent_timestamp->d_name) + "/edizon_save_metadata.json"); + if (metadataUsername.empty()) + metadataUsername = "By an unknown user [/restore]"; + else + metadataUsername = "By " + metadataUsername + " [/restore]"; + + backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); + backups.push_back(path.str() + "/" + std::string(ent_timestamp->d_name)); + backups.push_back(std::string(ent_timestamp->d_name)); + } + closedir(dir_titles); + } + + //Read batch saves + if ((dir_batch = opendir(EDIZON_DIR "/batch_saves")) != nullptr) { + while ((ent_timestamp = readdir(dir_batch)) != nullptr) { + path.str(""); + path << EDIZON_DIR "/batch_saves/" << std::string(ent_timestamp->d_name); + if ((dir_users = opendir(path.str().c_str())) != nullptr) { + while ((ent_user = readdir(dir_users)) != nullptr) { + if (ent_user->d_type != DT_DIR) continue; + + path.str(""); + path << EDIZON_DIR "/batch_saves/" << std::string(ent_timestamp->d_name) << "/" << std::string(ent_user->d_name) << "/" << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); + if ((dir_titles = opendir(path.str().c_str())) != nullptr) { + metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/edizon_save_metadata.json"); + + if (metadataUsername.empty()) + metadataUsername = "By an unknown user [Batch]"; + else + metadataUsername = "By " + metadataUsername + " [Batch]"; + + backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); + backups.push_back(path.str()); + backups.push_back(std::string(ent_timestamp->d_name)); + + closedir(dir_titles); + } + } + closedir(dir_users); + } + } + closedir(dir_batch); + } + + path.str(""); + + //Read root saves + path << EDIZON_DIR "/saves/" << std::setfill('0') << std::setw(16) << std::uppercase << std::hex << Title::g_currTitle->getTitleID(); + if ((dir_titles = opendir(path.str().c_str())) != nullptr) { + while ((ent_timestamp = readdir(dir_titles)) != nullptr) { + if (ent_timestamp->d_type != DT_DIR) continue; + + metadataUsername = GuiEditor::readMetaDataUsername(path.str() + "/" + std::string(ent_timestamp->d_name) + "/edizon_save_metadata.json"); + if (metadataUsername.empty()) + metadataUsername = "By an unknown user"; + else + metadataUsername = "By " + metadataUsername; + + backups.push_back(std::string(ent_timestamp->d_name) + ", " + metadataUsername); + backups.push_back(path.str() + "/" + std::string(ent_timestamp->d_name)); + backups.push_back(std::string(ent_timestamp->d_name)); + } + closedir(dir_titles); + } + + + for (auto iter = backups.begin(); iter != backups.end();) { + m_backupTitles.push_back(*iter++); + m_backupPaths.push_back(*iter++); + m_backupFolderNames.push_back(*iter++); + } + + std::reverse(m_backupTitles.begin(), m_backupTitles.end()); + std::reverse(m_backupPaths.begin(), m_backupPaths.end()); + std::reverse(m_backupFolderNames.begin(), m_backupFolderNames.end()); + +} + +std::string GuiEditor::readMetaDataUsername(std::string path) { + json metadata_json; + + std::ifstream metadata_file (path); + + if (metadata_file.is_open()) { + metadata_file >> metadata_json; + metadata_file.close(); + try { + return metadata_json["user_name"].get(); + } catch (json::parse_error& e) { } + } + + return ""; +} + +void GuiEditor::updateSaveFileList(std::vector saveFilePath, std::string files, u8 configIndex) { + DIR *dir; + struct dirent *ent; + FsFileSystem fs; + + std::vector pathsOld; + std::vector paths; + + if (mountSaveByTitleAccountIDs(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), fs)) + return; + + if (saveFilePath[0] != "") { + dir = opendir("save:/"); + + while ((ent = readdir(dir)) != nullptr) { + if (std::regex_match(std::string(ent->d_name), std::regex(saveFilePath[0]))) { + pathsOld.push_back(std::string(ent->d_name) + "/"); + } + } + + closedir(dir); + + for (u16 i = 1; i < saveFilePath.size(); i++) { + for (auto path : pathsOld) { + dir = opendir(path.c_str()); + while ((ent = readdir(dir)) != nullptr) { + if (std::regex_match(std::string(ent->d_name), std::regex(saveFilePath[i]))) { + std::string newPath = path; + newPath += "/"; + newPath += ent->d_name; + paths.push_back(newPath); + } + } + + closedir(dir); + } + + pathsOld = paths; + paths.clear(); + } + } else pathsOld.push_back(""); + + for (auto path : pathsOld) { + std::string finalSaveFilePath = std::string("save:/") + path; + if ((dir = opendir(finalSaveFilePath.c_str())) != nullptr) { + std::regex validSaveFileNames(files); + + while ((ent = readdir(dir)) != nullptr) { + if (std::regex_match(ent->d_name, validSaveFileNames)) + m_saveFiles.push_back({ path + ent->d_name, configIndex }); + } + closedir(dir); + } + } + + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + +} + +void uploadBackup(std::string path, std::string fileName) { + UploadManager um; + static std::stringstream hashStr; + + (new MessageBox("Uploading savefile...\n \nPress \uE0E1 to cancel.", MessageBox::NONE))->show(); + requestDraw(); + + char serial[0x19]; + u8 serialHash[0x20]; + setsysGetSerialNumber(serial); + + + Sha256Context shaCtx; + sha256ContextCreate(&shaCtx); + sha256ContextUpdate(&shaCtx, (u8 *)serial, 0x19); + sha256ContextGetHash(&shaCtx, serialHash); + + hashStr.str(""); + + for (u8 i = 0; i < 0x20; i++) { + hashStr << std::hex << (serialHash[i] & 0x0F); + hashStr << std::hex << (serialHash[i] >> 4); + } + + static std::string retCode; + retCode = um.upload(path, fileName, Title::g_currTitle, hashStr.str()); + retCode = retCode.substr(0, retCode.find("\n") - 1); + + if (retCode.length() == 6) { + (new MessageBox("", MessageBox::OKAY))->setCustomDraw([&](Gui *gui, s16 x, s16 y){ + u32 w, h; + gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, currTheme.textColor, "Upload finished!\n \n Visit edizon.werwolv.net and enter this code\n to get your link!", ALIGNED_CENTER); + + gui->getTextDimensions(font24, retCode.c_str(), &w, &h); + + gui->drawRectangle(x + (780 / 2) - (w / 2) - 20, y + 210, w + 40, h + 20, currTheme.tooltipColor); + gui->drawTextAligned(font24, x + (780 / 2), y + 210, currTheme.textColor, retCode.c_str(), ALIGNED_CENTER); + })->show(); + } + else + (new MessageBox("Upload failed!\n \n" + retCode, MessageBox::OKAY))->show(); +} + +void GuiEditor::onInput(u32 kdown) { +if (GuiEditor::g_currSaveFileName == "") { /* No savefile loaded */ + + if (kdown & KEY_MINUS) { + if (m_configFileResult != 0) return; + m_saveFiles.clear(); + + for (u8 configIndex = 0; configIndex < EditorConfigParser::getConfigFile().size(); configIndex++) + updateSaveFileList(EditorConfigParser::getConfigFile()[configIndex]["saveFilePaths"], EditorConfigParser::getConfigFile()[configIndex]["files"], configIndex); + + static std::vector saveFileNames; + + saveFileNames.clear(); + + for (auto saveFile : m_saveFiles) + saveFileNames.push_back(saveFile.fileName); + + (new ListSelector("Edit save file", "\uE0E0 Select \uE0E1 Back", saveFileNames))->setInputAction([&](u32 k, u16 selectedItem) { + if (k & KEY_A) { + if (m_saveFiles.size() != 0) { + size_t length; + Widget::g_selectedWidgetIndex = 0; + Widget::g_selectedCategory = ""; + Widget::g_selectedRow = CATEGORIES; + Widget::g_categoryYOffset = 0; + + (new MessageBox("Starting up editor...", MessageBox::NONE))->show(); + requestDraw(); + Gui::g_currMessageBox->hide(); + + GuiEditor::g_currSaveFileName = m_saveFiles[Gui::g_currListSelector->selectedItem].fileName.c_str(); + + if (loadSaveFile(&GuiEditor::g_currSaveFile, &length, Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), GuiEditor::g_currSaveFileName.c_str()) == 0) { + m_interpreter->setSaveFileBuffer(&g_currSaveFile[0], length, EditorConfigParser::getOptionalValue(EditorConfigParser::getConfigFile(), "encoding", "ascii")); + EditorConfigParser::createWidgets(m_widgets, *m_interpreter, this->m_saveFiles[selectedItem].configIndex); + + if (EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["startupMessage"] != nullptr) + (new MessageBox(EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["startupMessage"], MessageBox::OKAY))->show(); + + if(!m_interpreter->initialize(EditorConfigParser::getConfigFile()[this->m_saveFiles[selectedItem].configIndex]["filetype"])) { + m_interpreter->deinitialize(); + Gui::g_currMessageBox->hide(); + + GuiEditor::g_currSaveFile.clear(); + GuiEditor::g_currSaveFileName = ""; + + for (auto const& [category, widgets] : m_widgets) + for(auto widget : widgets) + delete widget.widget; + + m_widgets.clear(); + Widget::g_categories.clear(); + (new Snackbar("Failed to start script interpreter! Syntax error or script not found."))->show(); + + Gui::g_currListSelector->hide(); + return; + } + } + else { + (new Snackbar("Failed to load save file! Is it empty?"))->show(); + GuiEditor::g_currSaveFile.clear(); + GuiEditor::g_currSaveFileName = ""; + + for (auto const& [category, widgets] : m_widgets) + for(auto widget : widgets) + delete widget.widget; + + m_widgets.clear(); + } + Gui::g_currListSelector->hide(); + } + } + })->show(); + } + + if (kdown & KEY_B) { + Gui::g_nextGui = GUI_MAIN; + } + + if (kdown & KEY_X) { + s16 res; + + time_t t = time(nullptr); + static char backupName[65]; + std::stringstream initialText; + initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); + if(!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) + return; + + (new MessageBox("Extracting save file.\n \nThis may take a while...", MessageBox::NONE))->show(); + requestDraw(); + + if(!(res = backupSave(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), false, backupName))) { + (new MessageBox("Successfully created backup!\n \n Would you like to upload it to anonfile.com?", MessageBox::YES_NO))->setSelectionAction([&](u8 selection) { + if (selection) { + std::stringstream backupPath; + backupPath << EDIZON_DIR "/saves/" << std::uppercase << std::setfill('0') + << std::setw(sizeof(Title::g_currTitle->getTitleID())*2) + << std::hex << Title::g_currTitle->getTitleID() + << "/" << std::string(backupName); + + uploadBackup(backupPath.str(), backupName); + } else Gui::g_currMessageBox->hide(); + })->show(); + + } + else { + Gui::g_currMessageBox->hide(); + switch(res) { + case 1: (new Snackbar("Failed to mount save file!"))->show(); break; + case 2: (new Snackbar("A backup with this name already exists!"))->show(); break; + case 3: (new Snackbar("Failed to create backup!"))->show(); break; + } + } + } + + if (kdown & KEY_Y) { + updateBackupList(); + + (new ListSelector("Restore Backup", "\uE0F0 Upload \uE0E0 Restore \uE0E2 Delete \uE0E1 Back", m_backupTitles))->setInputAction([&](u32 k, u16 selectedItem){ + if (k & KEY_A) { + if (m_backupTitles.size() != 0) { + (new MessageBox("Are you sure you want to inject this backup?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { + if (selection) { + s16 res; + + if(!(res = restoreSave(Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), m_backupPaths[Gui::g_currListSelector->selectedItem].c_str()))) + (new Snackbar("Successfully restored backup!"))->show(); + else (new Snackbar("An error occured while restoring the backup! Error " + std::to_string(res)))->show(); + + Gui::g_currListSelector->hide(); + Gui::g_currMessageBox->hide(); + } else Gui::g_currMessageBox->hide(); + })->show(); + } + } + + if (k & KEY_X) { + std::stringstream path; + deleteDirRecursively(m_backupPaths[Gui::g_currListSelector->selectedItem].c_str(), false); + updateBackupList(); + + if (Gui::g_currListSelector->selectedItem == m_backupTitles.size() && Gui::g_currListSelector->selectedItem > 0) + Gui::g_currListSelector->selectedItem--; + } + + if (k & KEY_MINUS) { + uploadBackup(m_backupPaths[Gui::g_currListSelector->selectedItem], m_backupFolderNames[Gui::g_currListSelector->selectedItem]); + + Gui::g_currListSelector->hide(); + } + })->show(); + } + + if (kdown & KEY_ZL) { + Title *nextTitle = nullptr; + bool isCurrTitle = false; + + for (auto title : Title::g_titles) { + if (isCurrTitle) { + nextTitle = title.second; + + break; + } + + isCurrTitle = title.second == Title::g_currTitle; + } + + if (nextTitle == nullptr) + nextTitle = Title::g_titles.begin()->second; + + Title::g_currTitle = nextTitle; + Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; + Gui::g_nextGui = GUI_EDITOR; + } + + if (kdown & KEY_ZR) { + Account *nextAccount = nullptr; + bool isCurrAccount = false; + + for (auto userID : Title::g_currTitle->getUserIDs()) { + if (isCurrAccount) { + nextAccount = Account::g_accounts[userID]; + break; + } + isCurrAccount = userID == Account::g_currAccount->getUserID(); + } + + if (nextAccount == nullptr) + nextAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; + + if (Title::g_currTitle->getUserIDs().size() != 1) { + Account::g_currAccount = nextAccount; + Gui::g_nextGui = GUI_EDITOR; + } else nextAccount = nullptr; + } + } /* Savefile loaded */ + else { + if (Widget::g_selectedRow == WIDGETS) { /* Widgets row */ + if (kdown & KEY_L) { + if (Widget::g_widgetPage > 0) + Widget::g_widgetPage--; + Widget::g_selectedWidgetIndex = WIDGETS_PER_PAGE * Widget::g_widgetPage; + } + + if (kdown & KEY_R) { + if (Widget::g_widgetPage < Widget::g_widgetPageCnt[Widget::g_selectedCategory] - 1) + Widget::g_widgetPage++; + Widget::g_selectedWidgetIndex = WIDGETS_PER_PAGE * Widget::g_widgetPage ; + } + + if (kdown & KEY_B || kdown & KEY_LSTICK_LEFT || kdown & KEY_RSTICK_LEFT) { + Widget::g_selectedRow = CATEGORIES; + Widget::g_selectedWidgetIndex = std::distance(Widget::g_categories.begin(), std::find(Widget::g_categories.begin(), Widget::g_categories.end(), Widget::g_selectedCategory)); + } + + if (kdown & KEY_LSTICK_UP || kdown & KEY_RSTICK_UP) { + if (Widget::g_selectedWidgetIndex > 0) + Widget::g_selectedWidgetIndex--; + Widget::g_widgetPage = floor(Widget::g_selectedWidgetIndex / WIDGETS_PER_PAGE); + } + + if (kdown & KEY_LSTICK_DOWN || kdown & KEY_RSTICK_DOWN) { + if (Widget::g_selectedWidgetIndex < m_widgets[Widget::g_selectedCategory].size() - 1) + Widget::g_selectedWidgetIndex++; + Widget::g_widgetPage = floor(Widget::g_selectedWidgetIndex / WIDGETS_PER_PAGE); + } + + } else { /* Categories row */ + if (kdown & KEY_B) { + (new MessageBox("Are you sure you want to discard your changes?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { + if (selection) { + m_interpreter->deinitialize(); + + GuiEditor::g_currSaveFile.clear(); + GuiEditor::g_currSaveFileName = ""; + + for (auto const& [category, widgets] : m_widgets) + for(auto widget : widgets) + delete widget.widget; + + m_widgets.clear(); + Widget::g_categories.clear(); + Gui::g_currMessageBox->hide(); + } else Gui::g_currMessageBox->hide(); + })->show(); + + return; + } + + if (kdown & KEY_LSTICK_UP || kdown & KEY_RSTICK_UP) { + if (Widget::g_selectedWidgetIndex > 0) { + Widget::g_selectedWidgetIndex--; + + if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 7 && Widget::g_categoryYOffset != 0) + Widget::g_categoryYOffset--; + } + Widget::g_selectedCategory = Widget::g_categories[Widget::g_selectedWidgetIndex]; + Widget::g_widgetPage = 0; + } + + if (kdown & KEY_LSTICK_DOWN || kdown & KEY_RSTICK_DOWN) { + if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 1) { + Widget::g_selectedWidgetIndex++; + + if (Widget::g_selectedWidgetIndex > 6 && Widget::g_categoryYOffset < Widget::g_categories.size() - 8) + Widget::g_categoryYOffset++; + } + Widget::g_selectedCategory = Widget::g_categories[Widget::g_selectedWidgetIndex]; + Widget::g_widgetPage = 0; + } + } + /* Categories and widgets row */ + if (kdown & KEY_X) { + (new MessageBox(EditorConfigParser::g_betaTitles[Title::g_currTitle->getTitleID()] ? "Do you want to apply these changes? \n Make sure you have a working backup of your \n save data as this config is still in beta!" :"Do you want to apply these changes?", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { + if (selection) { + std::vector buffer; + + m_interpreter->getModifiedSaveFile(buffer); + + if(buffer.empty()) + (new Snackbar("Injection of modified values failed!"))->show(); + else { + if(!storeSaveFile(&buffer[0], buffer.size(), Title::g_currTitle->getTitleID(), Account::g_currAccount->getUserID(), GuiEditor::g_currSaveFileName.c_str())) + (new Snackbar("Successfully injected modified values!"))->show(); + else + (new Snackbar("Injection of modified values failed!"))->show(); + } + + m_interpreter->deinitialize(); + GuiEditor::g_currSaveFile.clear(); + GuiEditor::g_currSaveFileName = ""; + + Widget::g_widgetPage = 0; + + for (auto const& [category, widgets] : m_widgets) + for(auto widget : widgets) + delete widget.widget; + + Widget::g_categories.clear(); + m_widgets.clear(); + Gui::g_currMessageBox->hide(); + } else Gui::g_currMessageBox->hide(); + })->show(); + + return; + } + + Widget::handleInput(kdown, m_widgets); + } +} + +void GuiEditor::onTouch(touchPosition &touch) { + if (GuiEditor::g_currSaveFileName == "") { + if (touch.px < 128 && touch.py < 128) { + Title *nextTitle = nullptr; + bool isCurrTitle = false; + + for (auto title : Title::g_titles) { + if (isCurrTitle) { + nextTitle = title.second; + break; + } + + isCurrTitle = title.second == Title::g_currTitle; + } + + if (nextTitle == nullptr) + nextTitle = Title::g_titles.begin()->second; + + Title::g_currTitle = nextTitle; + Account::g_currAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; + Gui::g_nextGui = GUI_EDITOR; + } + + if (touch.px > Gui::g_framebuffer_width - 128 && touch.py < 128) { + Account *nextAccount = nullptr; + bool isCurrAccount = false; + + for (auto userID : Title::g_currTitle->getUserIDs()) { + if (isCurrAccount) { + nextAccount = Account::g_accounts[userID]; + break; + } + isCurrAccount = userID == Account::g_currAccount->getUserID(); + } + + if (nextAccount == nullptr) + nextAccount = Account::g_accounts[Title::g_currTitle->getUserIDs()[0]]; + + if (Title::g_currTitle->getUserIDs().size() != 1) { + Account::g_currAccount = nextAccount; + Gui::g_nextGui = GUI_EDITOR; + } else nextAccount = nullptr; + } + } else { + //s8 widgetTouchPos = floor((touch.py - 150) / (static_cast(WIDGET_HEIGHT) + WIDGET_SEPARATOR)) + WIDGETS_PER_PAGE * Widget::g_widgetPage; + Widget::handleTouch(touch, m_widgets); + } +} + +void GuiEditor::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} diff --git a/source/guis/gui_guide.cpp b/source/guis/gui_guide.cpp index 630bd86b..772ad0e5 100644 --- a/source/guis/gui_guide.cpp +++ b/source/guis/gui_guide.cpp @@ -1,134 +1,134 @@ -#include "guis/gui_guide.hpp" -#include "json.hpp" - -using json = nlohmann::json; - -GuiGuide::GuiGuide() : Gui() { - std::ifstream configFile("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/config.json"); - json configJson; - configFile >> configJson; - - configFile.close(); - - try { - for (auto image : configJson["images"]) { - std::ifstream data("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/" + image["path"].get(), std::ios::binary | std::ios::ate); - GuiGuide::guide_obj_t imageObj = { 0 }; - - imageObj.length = data.tellg(); - imageObj.data = new char[imageObj.length]; - imageObj.x = image["x"]; - imageObj.y = image["y"]; - imageObj.w = image["w"]; - imageObj.h = image["h"]; - imageObj.title = image["title"]; - imageObj.type = GuiGuide::guide_obj_t::TYPE_IMAGE; - - data.seekg(0, std::ios::beg); - - data.read(imageObj.data, imageObj.length); - data.close(); - - - m_objects.push_back(imageObj); - } - } catch(json::parse_error& e) { } - - try { - for (auto text : configJson["text"]) { - std::ifstream data("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/" + text["path"].get(), std::ios::ate); - GuiGuide::guide_obj_t textObj = { 0 }; - - textObj.length = data.tellg(); - textObj.data = new char[textObj.length + 1](); - textObj.x = text["x"]; - textObj.y = text["y"]; - textObj.type = GuiGuide::guide_obj_t::TYPE_TEXT; - - data.seekg(0, std::ios::beg); - - data.read(textObj.data, textObj.length); - data.close(); - - textObj.title = text["title"]; - - m_objects.push_back(textObj); - } - } catch(json::parse_error& e) { } -} - -GuiGuide::~GuiGuide() { - for (GuiGuide::guide_obj_t obj : m_objects) { - delete[] obj.data; - } -} - -void GuiGuide::update() { - Gui::update(); -} - -void GuiGuide::draw() { - Gui::beginDraw(); - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 87, 1220, 1, currTheme.textColor); - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); - Gui::drawTextAligned(fontTitle, 70, 60, currTheme.textColor, "\uE142", ALIGNED_LEFT); - Gui::drawTextAligned(font24, 70, 23, currTheme.textColor, " Quick start guide", ALIGNED_LEFT); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0E4 Previous \uE0E5 Next \uE0E1 Back", ALIGNED_RIGHT); - - color_t darkened = currTheme.backgroundColor; - darkened.a = 0x9F; - - if (GuiGuide::g_selectedPage == 1) - Gui::drawRectangled(800, Gui::g_framebuffer_height - 50, 200, 50, darkened); - - if (GuiGuide::g_selectedPage == GUIDE_PAGE_CNT) - Gui::drawRectangled(1000, Gui::g_framebuffer_height - 50, 110, 50, darkened); - - for (GuiGuide::guide_obj_t obj : m_objects) { - if (obj.type == GuiGuide::guide_obj_t::TYPE_TEXT) { - Gui::drawTextAligned(font24, obj.x, obj.y, currTheme.textColor, obj.title.c_str(), ALIGNED_LEFT); - Gui::drawTextAligned(font24, obj.x + 1, obj.y, currTheme.textColor, obj.title.c_str(), ALIGNED_LEFT); - - Gui::drawTextAligned(font14, obj.x + 20, obj.y + 45, currTheme.textColor, obj.data, ALIGNED_LEFT); - } - else { - Gui::drawImage(obj.x, obj.y, obj.w, obj.h, (u8*)obj.data, IMAGE_MODE_RGBA32); - Gui::drawTextAligned(font14, obj.x + obj.w - 20, obj.y + obj.h + 5, currTheme.textColor, obj.title.c_str(), ALIGNED_RIGHT); - } - } - - Gui::endDraw(); -} - -void GuiGuide::onInput(u32 kdown) { - if (kdown & KEY_B) { - GuiGuide::g_selectedPage = 1; - Gui::g_nextGui = GUI_MAIN; - return; - } - if (kdown & KEY_R) { - - if (GuiGuide::g_selectedPage < GUIDE_PAGE_CNT) - GuiGuide::g_selectedPage++; - Gui::g_nextGui = GUI_GUIDE; - return; - } - - if (kdown & KEY_L) { - if (GuiGuide::g_selectedPage > 1) - GuiGuide::g_selectedPage--; - Gui::g_nextGui = GUI_GUIDE; - return; - } -} - -void GuiGuide::onTouch(touchPosition &touch) { - -} - -void GuiGuide::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} +#include "guis/gui_guide.hpp" +#include "json.hpp" + +using json = nlohmann::json; + +GuiGuide::GuiGuide() : Gui() { + std::ifstream configFile("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/config.json"); + json configJson; + configFile >> configJson; + + configFile.close(); + + try { + for (auto image : configJson["images"]) { + std::ifstream data("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/" + image["path"].get(), std::ios::binary | std::ios::ate); + GuiGuide::guide_obj_t imageObj = { 0 }; + + imageObj.length = data.tellg(); + imageObj.data = new char[imageObj.length]; + imageObj.x = image["x"]; + imageObj.y = image["y"]; + imageObj.w = image["w"]; + imageObj.h = image["h"]; + imageObj.title = image["title"]; + imageObj.type = GuiGuide::guide_obj_t::TYPE_IMAGE; + + data.seekg(0, std::ios::beg); + + data.read(imageObj.data, imageObj.length); + data.close(); + + + m_objects.push_back(imageObj); + } + } catch(json::parse_error& e) { } + + try { + for (auto text : configJson["text"]) { + std::ifstream data("romfs:/guide/" + std::to_string((g_selectedPage / 6) + 1) + "/" + std::to_string(g_selectedPage) + "/" + text["path"].get(), std::ios::ate); + GuiGuide::guide_obj_t textObj = { 0 }; + + textObj.length = data.tellg(); + textObj.data = new char[textObj.length + 1](); + textObj.x = text["x"]; + textObj.y = text["y"]; + textObj.type = GuiGuide::guide_obj_t::TYPE_TEXT; + + data.seekg(0, std::ios::beg); + + data.read(textObj.data, textObj.length); + data.close(); + + textObj.title = text["title"]; + + m_objects.push_back(textObj); + } + } catch(json::parse_error& e) { } +} + +GuiGuide::~GuiGuide() { + for (GuiGuide::guide_obj_t obj : m_objects) { + delete[] obj.data; + } +} + +void GuiGuide::update() { + Gui::update(); +} + +void GuiGuide::draw() { + Gui::beginDraw(); + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 87, 1220, 1, currTheme.textColor); + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); + Gui::drawTextAligned(fontTitle, 70, 60, currTheme.textColor, "\uE142", ALIGNED_LEFT); + Gui::drawTextAligned(font24, 70, 23, currTheme.textColor, " Quick start guide", ALIGNED_LEFT); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 51, currTheme.textColor, "\uE0E4 Previous \uE0E5 Next \uE0E1 Back", ALIGNED_RIGHT); + + color_t darkened = currTheme.backgroundColor; + darkened.a = 0x9F; + + if (GuiGuide::g_selectedPage == 1) + Gui::drawRectangled(800, Gui::g_framebuffer_height - 50, 200, 50, darkened); + + if (GuiGuide::g_selectedPage == GUIDE_PAGE_CNT) + Gui::drawRectangled(1000, Gui::g_framebuffer_height - 50, 110, 50, darkened); + + for (GuiGuide::guide_obj_t obj : m_objects) { + if (obj.type == GuiGuide::guide_obj_t::TYPE_TEXT) { + Gui::drawTextAligned(font24, obj.x, obj.y, currTheme.textColor, obj.title.c_str(), ALIGNED_LEFT); + Gui::drawTextAligned(font24, obj.x + 1, obj.y, currTheme.textColor, obj.title.c_str(), ALIGNED_LEFT); + + Gui::drawTextAligned(font14, obj.x + 20, obj.y + 45, currTheme.textColor, obj.data, ALIGNED_LEFT); + } + else { + Gui::drawImage(obj.x, obj.y, obj.w, obj.h, (u8*)obj.data, IMAGE_MODE_RGBA32); + Gui::drawTextAligned(font14, obj.x + obj.w - 20, obj.y + obj.h + 5, currTheme.textColor, obj.title.c_str(), ALIGNED_RIGHT); + } + } + + Gui::endDraw(); +} + +void GuiGuide::onInput(u32 kdown) { + if (kdown & KEY_B) { + GuiGuide::g_selectedPage = 1; + Gui::g_nextGui = GUI_MAIN; + return; + } + if (kdown & KEY_R) { + + if (GuiGuide::g_selectedPage < GUIDE_PAGE_CNT) + GuiGuide::g_selectedPage++; + Gui::g_nextGui = GUI_GUIDE; + return; + } + + if (kdown & KEY_L) { + if (GuiGuide::g_selectedPage > 1) + GuiGuide::g_selectedPage--; + Gui::g_nextGui = GUI_GUIDE; + return; + } +} + +void GuiGuide::onTouch(touchPosition &touch) { + +} + +void GuiGuide::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} diff --git a/source/guis/gui_main.cpp b/source/guis/gui_main.cpp index c6381436..3cc2e462 100644 --- a/source/guis/gui_main.cpp +++ b/source/guis/gui_main.cpp @@ -1,499 +1,499 @@ -#include "guis/gui_main.hpp" - -#include "helpers/save.hpp" -#include "helpers/title.hpp" -#include "helpers/editor_config_parser.hpp" -#include "helpers/account.hpp" - -#include "beta_bin.h" -#include "edizon_logo_bin.h" - -#include -#include -#include -#include -#include - -#include "helpers/util.h" - -static s64 xOffset, xOffsetNext; -static bool finishedDrawing = true; -static s64 startOffset = 0; - -static color_t arrowColor; - -GuiMain::GuiMain() : Gui() { - updateEditableTitlesList(); - - arrowColor = COLOR_WHITE; -} - -GuiMain::~GuiMain() { - -} - -void GuiMain::update() { - Gui::update(); - - if (xOffset != xOffsetNext && finishedDrawing) { - double deltaOffset = xOffsetNext - xOffset; - double scrollSpeed = deltaOffset / 30.0F; - - if (xOffsetNext > xOffset) - xOffset += ceil((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); - else - xOffset += floor((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); - - startOffset = xOffsetNext; - } - - if (xOffset > 0) - arrowColor.a = arrowColor.a > 0 ? arrowColor.a - 1 : 0; - else - arrowColor.a = arrowColor.a < 0xFF ? arrowColor.a + 1 : 0xFF; -} - -void GuiMain::draw() { - s64 x = 0, y = 32, currItem = 0; - s64 selectedX = 0, selectedY = 0; - bool tmpEditableOnly = m_editableOnly; - static u32 splashCnt = 0; - - Gui::beginDraw(); - - finishedDrawing = false; - - #if SPLASH_ENABLED - - if (!Gui::g_splashDisplayed) { - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x5D, 0x4F, 0x4E, 0xFF)); - Gui::drawImage(Gui::g_framebuffer_width / 2 - 128, Gui::g_framebuffer_height / 2 - 128, 256, 256, edizon_logo_bin, IMAGE_MODE_BGR24); - - if (splashCnt++ >= 70) - Gui::g_splashDisplayed = true; - - Gui::endDraw(); - return; - } - - #endif - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); - - if (Title::g_titles.size() == 0) { - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No games or saves found on this system! Please press \uE0E1 to exit EdiZon!", ALIGNED_CENTER); - Gui::endDraw(); - return; - } - - if ((m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) > 10) { - Gui::drawRectangle(0, 544, Gui::g_framebuffer_width, 5, currTheme.tooltipColor); - - u32 scrollbarPos = (static_cast(xOffset) / (std::ceil(std::round(m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) / 4.0F) * 2 * 256)) * Gui::g_framebuffer_width; - u32 scrollbarWidth = static_cast(Gui::g_framebuffer_width) / ((std::round((m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) / 2.0F) * 2) / 10.0F); - - Gui::drawRectangle(scrollbarPos, 544, scrollbarWidth, 5, currTheme.tooltipTextColor); - } - - for (auto title : Title::g_titles) { - if (currItem == m_selected.titleIndex) { - selectedX = x - xOffset; - selectedY = y; - m_selected.titleId = title.first; - } - - if (!tmpEditableOnly || EditorConfigParser::g_editableTitles.count(title.first)) { - if (x - xOffset >= -256 && x - xOffset < Gui::g_framebuffer_width) { - Gui::drawImage(x - xOffset, y, 256, 256, title.second->getTitleIcon(), IMAGE_MODE_RGB24); - - if (EditorConfigParser::g_betaTitles[title.first]) - Gui::drawImage(x - xOffset, y, 150, 150, 256, 256, beta_bin, IMAGE_MODE_ABGR32); - - if (y == 320 || title.first == (--Title::g_titles.end())->first) - Gui::drawShadow(x - xOffset, y, 256, 256); - - if (title.first == Title::g_activeTitle) { - Gui::drawRectangled(x - xOffset, y, 256, 256, Gui::makeColor(0x30, 0x30, 0x30, 0xA0)); - Gui::drawTextAligned(fontTitle, x - xOffset + 245, y + 250, currTheme.selectedColor, "\uE12C", ALIGNED_RIGHT); - } - } - - y = y == 32 ? 288 : 32; - x = floor(++currItem / 2.0F) * 256; - } - } - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, 32, currTheme.selectedButtonColor); - Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 32); - - char timeBuffer[6]; - char batteryBuffer[5]; - getCurrTimeString(timeBuffer); - getCurrBatteryPercentage(batteryBuffer); - - Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 8, 3, currTheme.separatorColor, timeBuffer, ALIGNED_RIGHT); - Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 80, 3, currTheme.separatorColor, batteryBuffer, ALIGNED_RIGHT); - Gui::drawTextAligned(font14, 8, 3, currTheme.separatorColor, "EdiZon v" VERSION_STRING, ALIGNED_LEFT); - - Gui::drawRectangled(Gui::g_framebuffer_width - 72, 5, 7, 18, currTheme.separatorColor); - Gui::drawRectangled(Gui::g_framebuffer_width - 75, 8, 13, 18, currTheme.separatorColor); - - if (tmpEditableOnly && EditorConfigParser::g_editableTitles.size() == 0) { - Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No editable games found on this system!", ALIGNED_CENTER); - Gui::endDraw(); - return; - } - else { - if (m_selected.titleIndex != -1 && m_selected.extraOption == -1) { - Gui::drawRectangled(selectedX - 5, selectedY - 5, 266, 266, currTheme.highlightColor); - Gui::drawImage(selectedX, selectedY, 256, 256, Title::g_titles[m_selected.titleId]->getTitleIcon(), IMAGE_MODE_RGB24); - - if (EditorConfigParser::g_betaTitles[m_selected.titleId]) - Gui::drawImage(selectedX, selectedY, 150, 150, 256, 256, beta_bin, IMAGE_MODE_ABGR32); - - if (m_selected.titleId == Title::g_activeTitle) { - Gui::drawRectangled(selectedX, selectedY, 256, 256, Gui::makeColor(0x30, 0x30, 0x30, 0xA0)); - Gui::drawTextAligned(fontTitle, selectedX + 245, selectedY + 250, currTheme.selectedColor, "\uE12C", ALIGNED_RIGHT); - } - - Gui::drawShadow(selectedX - 5, selectedY - 5, 266, 266); - } - - if (m_selected.extraOption != -1) { - Gui::drawRectangled(455 + 150 * m_selected.extraOption, 557, 70, 70, currTheme.highlightColor); - } - - Gui::drawRectangled(458, 560, 64, 64, currTheme.selectedButtonColor); - Gui::drawRectangled(608, 560, 64, 64, currTheme.selectedButtonColor); - Gui::drawRectangled(758, 560, 64, 64, currTheme.selectedButtonColor); - - Gui::drawTextAligned(fontTitle, 469, 608, Gui::makeColor(0x11, 0x75, 0xFB, 0xFF), "\uE02B", ALIGNED_LEFT); - Gui::drawTextAligned(fontTitle, 619, 608, Gui::makeColor(0x34, 0xA8, 0x53, 0xFF), "\uE02E", ALIGNED_LEFT); - Gui::drawTextAligned(fontTitle, 769, 608, Gui::makeColor(0xEA, 0x43, 0x35, 0xFF), "\uE017", ALIGNED_LEFT); - - - Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); - - if (m_selected.extraOption == 0) - Gui::drawTextAligned(font14, 490, 623, currTheme.tooltipTextColor, "Cheats", ALIGNED_CENTER); - else if (m_selected.extraOption == 1) - Gui::drawTextAligned(font14, 640, 623, currTheme.tooltipTextColor, "Guide", ALIGNED_CENTER); - else if (m_selected.extraOption == 2) - Gui::drawTextAligned(font14, 790, 623, currTheme.tooltipTextColor, "About", ALIGNED_CENTER); - - std::string buttonHintStr = ""; - - buttonHintStr = !tmpEditableOnly ? "\uE0E6 Editable titles " : "\uE0E6 All titles "; - buttonHintStr += m_backupAll ? "(\uE0E7) + \uE0E2 Backup all " : "(\uE0E7) + \uE0E2 Backup "; - buttonHintStr += "\uE0E1 Back \uE0E0 OK"; - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, buttonHintStr.c_str(), ALIGNED_RIGHT); - - if (m_selected.titleIndex != -1) - Gui::drawTooltip(selectedX + 128, 288, Title::g_titles[m_selected.titleId]->getTitleName().c_str(), currTheme.tooltipColor, currTheme.tooltipTextColor, 0xFF, m_selected.titleIndex % 2); - } - - finishedDrawing = true; - - Gui::endDraw(); -} - -void GuiMain::onInput(u32 kdown) { - if (kdown & KEY_B) - Gui::g_requestExit = true; - - if (Title::g_titles.size() == 0) return; - - if (m_selected.extraOption == -1) { /* one of the titles is selected */ - if (kdown & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_A | KEY_X)) { - if (m_selected.titleIndex == -1 || (m_selected.titleIndex / 2 + 1) * 256 < xOffset || (m_selected.titleIndex / 2) * 256 > xOffset + 6 * 256) { - m_selected.titleIndex = std::ceil(xOffset / 256.0F) * 2; - return; - } - } - - if (kdown & KEY_LEFT) { - if (static_cast(m_selected.titleIndex - 2) >= 0) - m_selected.titleIndex -= 2; - } else if (kdown & KEY_RIGHT) { - if (static_cast(m_selected.titleIndex + 2) < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) - m_selected.titleIndex += 2; - } else if (kdown & KEY_UP) { - if ((m_selected.titleIndex % 2) == 1) { - m_selected.titleIndex--; - } - } else if (kdown & KEY_DOWN) { - if ((m_selected.titleIndex % 2) == 0) { - if (static_cast(m_selected.titleIndex + 1) < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) - m_selected.titleIndex++; - } else { - if (m_selected.titleIndex < (std::ceil(xOffset / 256.0F) * 2 + 4)) - m_selected.extraOption = 0; - else if (m_selected.titleIndex < (std::ceil(xOffset / 256.0F) * 2 + 6)) - m_selected.extraOption = 1; - else - m_selected.extraOption = 2; - - m_selected.titleIndex = -1; - } - } - - if (kdown & KEY_A) { - if (m_selected.titleId == Title::g_activeTitle) { - (new Snackbar("The save files of a running game cannot be accessed."))->show(); - return; - } - u128 userID = Gui::requestPlayerSelection(); - std::vector users = Title::g_titles[m_selected.titleId]->getUserIDs(); - - if(userID == 0x00) - return; - - if (std::find(users.begin(), users.end(), userID) != users.end()) { - Title::g_currTitle = Title::g_titles[m_selected.titleId]; - Account::g_currAccount = Account::g_accounts[userID]; - Gui::g_nextGui = GUI_EDITOR; - } else (new Snackbar("No save file for this user available!"))->show(); - } - - if (kdown & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT)) { - if (m_selected.titleIndex != -1) { - if (m_selected.titleIndex / 2 - (xOffset / 256) > 3) - xOffsetNext = std::min(static_cast((m_selected.titleIndex / 2 - 3) * 256), static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5) * 256)); - - if (m_selected.titleIndex / 2 - (xOffset / 256) < 1) - xOffsetNext = std::max((m_selected.titleIndex / 2 - 1) * 256, 0); - } - } - - if (kdown & KEY_X) { - if (m_selected.titleId == Title::g_activeTitle) { - (new Snackbar("The save files of a running game cannot be accessed."))->show(); - return; - } - - if (m_backupAll) { - (new MessageBox("Are you sure you want to backup all saves \n on this console? \n This might take a while.", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { - bool batchFailed = false; - - char backupName[65]; - time_t t = time(nullptr); - std::stringstream initialText; - initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); - - if (selection) { - if(!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) - return; - - (new MessageBox("Creating batch backup. \n \n This might take a while...", MessageBox::NONE))->show(); - requestDraw(); - - s16 res; - u16 failed_titles = 0; - - for (auto title : Title::g_titles) { - for (u128 userID : Title::g_titles[title.first]->getUserIDs()) { - if((res = backupSave(title.first, userID, true, backupName))) { - batchFailed = true; - failed_titles++; - } - } - - Gui::g_currMessageBox->hide(); - - if (!batchFailed) - (new Snackbar("Successfully created backups!"))->show(); - else { - std::stringstream errorMessage; - errorMessage << "Failed to backup " << failed_titles << " titles!"; - (new Snackbar(errorMessage.str()))->show(); - } - } - - Gui::g_currMessageBox->hide(); - } else Gui::g_currMessageBox->hide(); - })->show(); - } - else { - bool batchFailed = false; - s16 res; - - time_t t = time(nullptr); - char backupName[65]; - std::stringstream initialText; - initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); - - if (!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) - return; - - for (u128 userID : Title::g_titles[m_selected.titleId]->getUserIDs()) { - if((res = backupSave(m_selected.titleId, userID, true, backupName))) { - batchFailed = true; - } - } - - if (!batchFailed) - (new Snackbar("Successfully created backup!"))->show(); - else { - switch(res) { - case 1: (new Snackbar("Failed to mount save file!"))->show(); break; - case 2: (new Snackbar("A backup with this name already exists!"))->show(); break; - case 3: (new Snackbar("Failed to create backup!"))->show(); break; - } - } - } - } - } else { /* One of the extra options (Cheats, Tutorial or Credits) is selected */ - if (kdown & KEY_UP) { - m_selected.titleIndex = std::min(static_cast(std::ceil(xOffset / 256.0F) * 2 + 2 * m_selected.extraOption + 3), static_cast(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) - 1)); - m_selected.extraOption = -1; - } - else if (kdown & KEY_LEFT) { - if (m_selected.extraOption > 0) - m_selected.extraOption--; - } else if (kdown & KEY_RIGHT) { - if (m_selected.extraOption < 2) - m_selected.extraOption++; - } - - if (kdown & KEY_A) { - switch(m_selected.extraOption) { - case 0: - Gui::g_nextGui = GUI_CHEATS; - break; - case 1: - Gui::g_nextGui = GUI_GUIDE; - break; - case 2: - Gui::g_nextGui = GUI_ABOUT; - break; - default: break; - } - } - } - - if (kdown & KEY_ZL) { - m_editableOnly = !m_editableOnly; - m_selected.titleIndex = 0; - xOffsetNext = 0; - } - - m_backupAll = (kdown & KEY_ZR) > 0; -} - -void GuiMain::onTouch(touchPosition &touch) { - if (((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) == 0) return; - - u8 x = floor((touch.px + xOffset) / 256.0F); - u8 y = floor((touch.py - 32) / 256.0F); - u8 title = y + x * 2; - - if (touch.py < 32) return; - - if (y < 2) { - if (title < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) { - if (m_editableOnly && title > (EditorConfigParser::g_editableTitles.size() - 1)) return; - - if (m_selected.titleIndex == title) { - if (m_selected.titleId == Title::g_activeTitle) { - (new Snackbar("The save files of a running game cannot be accessed."))->show(); - return; - } - - u128 userID = Gui::requestPlayerSelection(); - - Title::g_currTitle = Title::g_titles[m_selected.titleId]; - std::vector users = Title::g_titles[m_selected.titleId]->getUserIDs(); - - if(userID == 0x00) - return; - - if (std::find(users.begin(), users.end(), userID) != users.end()) { - Title::g_currTitle = Title::g_titles[m_selected.titleId]; - Account::g_currAccount = Account::g_accounts[userID]; - Gui::g_nextGui = GUI_EDITOR; - } else (new Snackbar("No save file available for this user!"))->show(); - } - - m_selected.titleIndex = title; - m_selected.extraOption = -1; - } - } else { - if (touch.py > 560 && touch.py < 624) { - if (touch.px > 458 && touch.px < 522) { // Touched cheats button - if (m_selected.extraOption == 0) - Gui::g_nextGui = GUI_CHEATS; - else { - m_selected.extraOption = 0; - m_selected.titleIndex = -1; - } - } else if (touch.px > 608 && touch.px < 672) { // Touched guide button - if (m_selected.extraOption == 1) - Gui::g_nextGui = GUI_GUIDE; - else { - m_selected.extraOption = 1; - m_selected.titleIndex = -1; - } - } else if (touch.px > 758 && touch.px < 822) { // Touched information button - if (m_selected.extraOption == 2) - Gui::g_nextGui = GUI_ABOUT; - else { - m_selected.extraOption = 2; - m_selected.titleIndex = -1; - } - } - } - } -} - -inline s8 sign(s32 value) { - return (value > 0) - (value < 0); -} - -void GuiMain::onGesture(touchPosition startPosition, touchPosition currPosition, bool finish) { - static std::vector positions; - static touchPosition oldPosition; - - m_selected.titleIndex = -1; - m_selected.extraOption = -1; - - if (((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) == 0) return; - - if (finish) { - s32 velocity = (std::accumulate(positions.begin(), positions.end(), 0) / static_cast(positions.size())) * 2; - - xOffsetNext = std::min(std::max(xOffset + velocity * 1.5F, 0), 256 * static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5))); - - startOffset = xOffsetNext; - - positions.clear(); - oldPosition = {0}; - } - else { - xOffset = startOffset + (static_cast(startPosition.px) - static_cast(currPosition.px)); - xOffset = std::min(std::max(xOffset, 0), 256 * static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5))); - xOffsetNext = xOffset; - } - - if (oldPosition.px != 0x00) { - s32 pos = static_cast(oldPosition.px) - static_cast(currPosition.px); - if (std::abs(pos) < 400) - positions.push_back(pos); - } - - if (positions.size() > 10) - positions.erase(positions.begin()); - - oldPosition = currPosition; -} - -void GuiMain::updateEditableTitlesList() { - EditorConfigParser::g_editableTitles.clear(); - EditorConfigParser::g_betaTitles.clear(); - - for (auto title : Title::g_titles) { - if (EditorConfigParser::hasConfig(title.first) == 0) { - EditorConfigParser::g_editableTitles.insert({title.first, true}); - } - } -} +#include "guis/gui_main.hpp" + +#include "helpers/save.hpp" +#include "helpers/title.hpp" +#include "helpers/editor_config_parser.hpp" +#include "helpers/account.hpp" + +#include "beta_bin.h" +#include "edizon_logo_bin.h" + +#include +#include +#include +#include +#include + +#include "helpers/util.h" + +static s64 xOffset, xOffsetNext; +static bool finishedDrawing = true; +static s64 startOffset = 0; + +static color_t arrowColor; + +GuiMain::GuiMain() : Gui() { + updateEditableTitlesList(); + + arrowColor = COLOR_WHITE; +} + +GuiMain::~GuiMain() { + +} + +void GuiMain::update() { + Gui::update(); + + if (xOffset != xOffsetNext && finishedDrawing) { + double deltaOffset = xOffsetNext - xOffset; + double scrollSpeed = deltaOffset / 30.0F; + + if (xOffsetNext > xOffset) + xOffset += ceil((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); + else + xOffset += floor((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); + + startOffset = xOffsetNext; + } + + if (xOffset > 0) + arrowColor.a = arrowColor.a > 0 ? arrowColor.a - 1 : 0; + else + arrowColor.a = arrowColor.a < 0xFF ? arrowColor.a + 1 : 0xFF; +} + +void GuiMain::draw() { + s64 x = 0, y = 32, currItem = 0; + s64 selectedX = 0, selectedY = 0; + bool tmpEditableOnly = m_editableOnly; + static u32 splashCnt = 0; + + Gui::beginDraw(); + + finishedDrawing = false; + + #if SPLASH_ENABLED + + if (!Gui::g_splashDisplayed) { + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0x5D, 0x4F, 0x4E, 0xFF)); + Gui::drawImage(Gui::g_framebuffer_width / 2 - 128, Gui::g_framebuffer_height / 2 - 128, 256, 256, edizon_logo_bin, IMAGE_MODE_BGR24); + + if (splashCnt++ >= 70) + Gui::g_splashDisplayed = true; + + Gui::endDraw(); + return; + } + + #endif + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.backgroundColor); + + if (Title::g_titles.size() == 0) { + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No games or saves found on this system! Please press \uE0E1 to exit EdiZon!", ALIGNED_CENTER); + Gui::endDraw(); + return; + } + + if ((m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) > 10) { + Gui::drawRectangle(0, 544, Gui::g_framebuffer_width, 5, currTheme.tooltipColor); + + u32 scrollbarPos = (static_cast(xOffset) / (std::ceil(std::round(m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) / 4.0F) * 2 * 256)) * Gui::g_framebuffer_width; + u32 scrollbarWidth = static_cast(Gui::g_framebuffer_width) / ((std::round((m_editableOnly ? EditorConfigParser::g_editableTitles.size() : Title::g_titles.size()) / 2.0F) * 2) / 10.0F); + + Gui::drawRectangle(scrollbarPos, 544, scrollbarWidth, 5, currTheme.tooltipTextColor); + } + + for (auto title : Title::g_titles) { + if (currItem == m_selected.titleIndex) { + selectedX = x - xOffset; + selectedY = y; + m_selected.titleId = title.first; + } + + if (!tmpEditableOnly || EditorConfigParser::g_editableTitles.count(title.first)) { + if (x - xOffset >= -256 && x - xOffset < Gui::g_framebuffer_width) { + Gui::drawImage(x - xOffset, y, 256, 256, title.second->getTitleIcon(), IMAGE_MODE_RGB24); + + if (EditorConfigParser::g_betaTitles[title.first]) + Gui::drawImage(x - xOffset, y, 150, 150, 256, 256, beta_bin, IMAGE_MODE_ABGR32); + + if (y == 320 || title.first == (--Title::g_titles.end())->first) + Gui::drawShadow(x - xOffset, y, 256, 256); + + if (title.first == Title::g_activeTitle) { + Gui::drawRectangled(x - xOffset, y, 256, 256, Gui::makeColor(0x30, 0x30, 0x30, 0xA0)); + Gui::drawTextAligned(fontTitle, x - xOffset + 245, y + 250, currTheme.selectedColor, "\uE12C", ALIGNED_RIGHT); + } + } + + y = y == 32 ? 288 : 32; + x = floor(++currItem / 2.0F) * 256; + } + } + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, 32, currTheme.selectedButtonColor); + Gui::drawShadow(0, 0, Gui::g_framebuffer_width, 32); + + char timeBuffer[6]; + char batteryBuffer[5]; + getCurrTimeString(timeBuffer); + getCurrBatteryPercentage(batteryBuffer); + + Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 8, 3, currTheme.separatorColor, timeBuffer, ALIGNED_RIGHT); + Gui::drawTextAligned(font14, Gui::g_framebuffer_width - 80, 3, currTheme.separatorColor, batteryBuffer, ALIGNED_RIGHT); + Gui::drawTextAligned(font14, 8, 3, currTheme.separatorColor, "EdiZon v" VERSION_STRING, ALIGNED_LEFT); + + Gui::drawRectangled(Gui::g_framebuffer_width - 72, 5, 7, 18, currTheme.separatorColor); + Gui::drawRectangled(Gui::g_framebuffer_width - 75, 8, 13, 18, currTheme.separatorColor); + + if (tmpEditableOnly && EditorConfigParser::g_editableTitles.size() == 0) { + Gui::drawTextAligned(font24, (Gui::g_framebuffer_width / 2), (Gui::g_framebuffer_height / 2), currTheme.textColor, "No editable games found on this system!", ALIGNED_CENTER); + Gui::endDraw(); + return; + } + else { + if (m_selected.titleIndex != -1 && m_selected.extraOption == -1) { + Gui::drawRectangled(selectedX - 5, selectedY - 5, 266, 266, currTheme.highlightColor); + Gui::drawImage(selectedX, selectedY, 256, 256, Title::g_titles[m_selected.titleId]->getTitleIcon(), IMAGE_MODE_RGB24); + + if (EditorConfigParser::g_betaTitles[m_selected.titleId]) + Gui::drawImage(selectedX, selectedY, 150, 150, 256, 256, beta_bin, IMAGE_MODE_ABGR32); + + if (m_selected.titleId == Title::g_activeTitle) { + Gui::drawRectangled(selectedX, selectedY, 256, 256, Gui::makeColor(0x30, 0x30, 0x30, 0xA0)); + Gui::drawTextAligned(fontTitle, selectedX + 245, selectedY + 250, currTheme.selectedColor, "\uE12C", ALIGNED_RIGHT); + } + + Gui::drawShadow(selectedX - 5, selectedY - 5, 266, 266); + } + + if (m_selected.extraOption != -1) { + Gui::drawRectangled(455 + 150 * m_selected.extraOption, 557, 70, 70, currTheme.highlightColor); + } + + Gui::drawRectangled(458, 560, 64, 64, currTheme.selectedButtonColor); + Gui::drawRectangled(608, 560, 64, 64, currTheme.selectedButtonColor); + Gui::drawRectangled(758, 560, 64, 64, currTheme.selectedButtonColor); + + Gui::drawTextAligned(fontTitle, 469, 608, Gui::makeColor(0x11, 0x75, 0xFB, 0xFF), "\uE02B", ALIGNED_LEFT); + Gui::drawTextAligned(fontTitle, 619, 608, Gui::makeColor(0x34, 0xA8, 0x53, 0xFF), "\uE02E", ALIGNED_LEFT); + Gui::drawTextAligned(fontTitle, 769, 608, Gui::makeColor(0xEA, 0x43, 0x35, 0xFF), "\uE017", ALIGNED_LEFT); + + + Gui::drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73, 1220, 1, currTheme.textColor); + + if (m_selected.extraOption == 0) + Gui::drawTextAligned(font14, 490, 623, currTheme.tooltipTextColor, "Cheats", ALIGNED_CENTER); + else if (m_selected.extraOption == 1) + Gui::drawTextAligned(font14, 640, 623, currTheme.tooltipTextColor, "Guide", ALIGNED_CENTER); + else if (m_selected.extraOption == 2) + Gui::drawTextAligned(font14, 790, 623, currTheme.tooltipTextColor, "About", ALIGNED_CENTER); + + std::string buttonHintStr = ""; + + buttonHintStr = !tmpEditableOnly ? "\uE0E6 Editable titles " : "\uE0E6 All titles "; + buttonHintStr += m_backupAll ? "(\uE0E7) + \uE0E2 Backup all " : "(\uE0E7) + \uE0E2 Backup "; + buttonHintStr += "\uE0E1 Back \uE0E0 OK"; + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width - 50, Gui::g_framebuffer_height - 50, currTheme.textColor, buttonHintStr.c_str(), ALIGNED_RIGHT); + + if (m_selected.titleIndex != -1) + Gui::drawTooltip(selectedX + 128, 288, Title::g_titles[m_selected.titleId]->getTitleName().c_str(), currTheme.tooltipColor, currTheme.tooltipTextColor, 0xFF, m_selected.titleIndex % 2); + } + + finishedDrawing = true; + + Gui::endDraw(); +} + +void GuiMain::onInput(u32 kdown) { + if (kdown & KEY_B) + Gui::g_requestExit = true; + + if (Title::g_titles.size() == 0) return; + + if (m_selected.extraOption == -1) { /* one of the titles is selected */ + if (kdown & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_A | KEY_X)) { + if (m_selected.titleIndex == -1 || (m_selected.titleIndex / 2 + 1) * 256 < xOffset || (m_selected.titleIndex / 2) * 256 > xOffset + 6 * 256) { + m_selected.titleIndex = std::ceil(xOffset / 256.0F) * 2; + return; + } + } + + if (kdown & KEY_LEFT) { + if (static_cast(m_selected.titleIndex - 2) >= 0) + m_selected.titleIndex -= 2; + } else if (kdown & KEY_RIGHT) { + if (static_cast(m_selected.titleIndex + 2) < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) + m_selected.titleIndex += 2; + } else if (kdown & KEY_UP) { + if ((m_selected.titleIndex % 2) == 1) { + m_selected.titleIndex--; + } + } else if (kdown & KEY_DOWN) { + if ((m_selected.titleIndex % 2) == 0) { + if (static_cast(m_selected.titleIndex + 1) < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) + m_selected.titleIndex++; + } else { + if (m_selected.titleIndex < (std::ceil(xOffset / 256.0F) * 2 + 4)) + m_selected.extraOption = 0; + else if (m_selected.titleIndex < (std::ceil(xOffset / 256.0F) * 2 + 6)) + m_selected.extraOption = 1; + else + m_selected.extraOption = 2; + + m_selected.titleIndex = -1; + } + } + + if (kdown & KEY_A) { + if (m_selected.titleId == Title::g_activeTitle) { + (new Snackbar("The save files of a running game cannot be accessed."))->show(); + return; + } + u128 userID = Gui::requestPlayerSelection(); + std::vector users = Title::g_titles[m_selected.titleId]->getUserIDs(); + + if(userID == 0x00) + return; + + if (std::find(users.begin(), users.end(), userID) != users.end()) { + Title::g_currTitle = Title::g_titles[m_selected.titleId]; + Account::g_currAccount = Account::g_accounts[userID]; + Gui::g_nextGui = GUI_EDITOR; + } else (new Snackbar("No save file for this user available!"))->show(); + } + + if (kdown & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT)) { + if (m_selected.titleIndex != -1) { + if (m_selected.titleIndex / 2 - (xOffset / 256) > 3) + xOffsetNext = std::min(static_cast((m_selected.titleIndex / 2 - 3) * 256), static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5) * 256)); + + if (m_selected.titleIndex / 2 - (xOffset / 256) < 1) + xOffsetNext = std::max((m_selected.titleIndex / 2 - 1) * 256, 0); + } + } + + if (kdown & KEY_X) { + if (m_selected.titleId == Title::g_activeTitle) { + (new Snackbar("The save files of a running game cannot be accessed."))->show(); + return; + } + + if (m_backupAll) { + (new MessageBox("Are you sure you want to backup all saves \n on this console? \n This might take a while.", MessageBox::YES_NO))->setSelectionAction([&](s8 selection) { + bool batchFailed = false; + + char backupName[65]; + time_t t = time(nullptr); + std::stringstream initialText; + initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); + + if (selection) { + if(!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) + return; + + (new MessageBox("Creating batch backup. \n \n This might take a while...", MessageBox::NONE))->show(); + requestDraw(); + + s16 res; + u16 failed_titles = 0; + + for (auto title : Title::g_titles) { + for (u128 userID : Title::g_titles[title.first]->getUserIDs()) { + if((res = backupSave(title.first, userID, true, backupName))) { + batchFailed = true; + failed_titles++; + } + } + + Gui::g_currMessageBox->hide(); + + if (!batchFailed) + (new Snackbar("Successfully created backups!"))->show(); + else { + std::stringstream errorMessage; + errorMessage << "Failed to backup " << failed_titles << " titles!"; + (new Snackbar(errorMessage.str()))->show(); + } + } + + Gui::g_currMessageBox->hide(); + } else Gui::g_currMessageBox->hide(); + })->show(); + } + else { + bool batchFailed = false; + s16 res; + + time_t t = time(nullptr); + char backupName[65]; + std::stringstream initialText; + initialText << std::put_time(std::gmtime(&t), "%Y%m%d_%H%M%S"); + + if (!Gui::requestKeyboardInput("Backup name", "Please enter a name for the backup to be saved under.", initialText.str(), SwkbdType_QWERTY, backupName, 32)) + return; + + for (u128 userID : Title::g_titles[m_selected.titleId]->getUserIDs()) { + if((res = backupSave(m_selected.titleId, userID, true, backupName))) { + batchFailed = true; + } + } + + if (!batchFailed) + (new Snackbar("Successfully created backup!"))->show(); + else { + switch(res) { + case 1: (new Snackbar("Failed to mount save file!"))->show(); break; + case 2: (new Snackbar("A backup with this name already exists!"))->show(); break; + case 3: (new Snackbar("Failed to create backup!"))->show(); break; + } + } + } + } + } else { /* One of the extra options (Cheats, Tutorial or Credits) is selected */ + if (kdown & KEY_UP) { + m_selected.titleIndex = std::min(static_cast(std::ceil(xOffset / 256.0F) * 2 + 2 * m_selected.extraOption + 3), static_cast(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) - 1)); + m_selected.extraOption = -1; + } + else if (kdown & KEY_LEFT) { + if (m_selected.extraOption > 0) + m_selected.extraOption--; + } else if (kdown & KEY_RIGHT) { + if (m_selected.extraOption < 2) + m_selected.extraOption++; + } + + if (kdown & KEY_A) { + switch(m_selected.extraOption) { + case 0: + Gui::g_nextGui = GUI_CHEATS; + break; + case 1: + Gui::g_nextGui = GUI_GUIDE; + break; + case 2: + Gui::g_nextGui = GUI_ABOUT; + break; + default: break; + } + } + } + + if (kdown & KEY_ZL) { + m_editableOnly = !m_editableOnly; + m_selected.titleIndex = 0; + xOffsetNext = 0; + } + + m_backupAll = (kdown & KEY_ZR) > 0; +} + +void GuiMain::onTouch(touchPosition &touch) { + if (((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) == 0) return; + + u8 x = floor((touch.px + xOffset) / 256.0F); + u8 y = floor((touch.py - 32) / 256.0F); + u8 title = y + x * 2; + + if (touch.py < 32) return; + + if (y < 2) { + if (title < ((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size())) { + if (m_editableOnly && title > (EditorConfigParser::g_editableTitles.size() - 1)) return; + + if (m_selected.titleIndex == title) { + if (m_selected.titleId == Title::g_activeTitle) { + (new Snackbar("The save files of a running game cannot be accessed."))->show(); + return; + } + + u128 userID = Gui::requestPlayerSelection(); + + Title::g_currTitle = Title::g_titles[m_selected.titleId]; + std::vector users = Title::g_titles[m_selected.titleId]->getUserIDs(); + + if(userID == 0x00) + return; + + if (std::find(users.begin(), users.end(), userID) != users.end()) { + Title::g_currTitle = Title::g_titles[m_selected.titleId]; + Account::g_currAccount = Account::g_accounts[userID]; + Gui::g_nextGui = GUI_EDITOR; + } else (new Snackbar("No save file available for this user!"))->show(); + } + + m_selected.titleIndex = title; + m_selected.extraOption = -1; + } + } else { + if (touch.py > 560 && touch.py < 624) { + if (touch.px > 458 && touch.px < 522) { // Touched cheats button + if (m_selected.extraOption == 0) + Gui::g_nextGui = GUI_CHEATS; + else { + m_selected.extraOption = 0; + m_selected.titleIndex = -1; + } + } else if (touch.px > 608 && touch.px < 672) { // Touched guide button + if (m_selected.extraOption == 1) + Gui::g_nextGui = GUI_GUIDE; + else { + m_selected.extraOption = 1; + m_selected.titleIndex = -1; + } + } else if (touch.px > 758 && touch.px < 822) { // Touched information button + if (m_selected.extraOption == 2) + Gui::g_nextGui = GUI_ABOUT; + else { + m_selected.extraOption = 2; + m_selected.titleIndex = -1; + } + } + } + } +} + +inline s8 sign(s32 value) { + return (value > 0) - (value < 0); +} + +void GuiMain::onGesture(touchPosition startPosition, touchPosition currPosition, bool finish) { + static std::vector positions; + static touchPosition oldPosition; + + m_selected.titleIndex = -1; + m_selected.extraOption = -1; + + if (((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) == 0) return; + + if (finish) { + s32 velocity = (std::accumulate(positions.begin(), positions.end(), 0) / static_cast(positions.size())) * 2; + + xOffsetNext = std::min(std::max(xOffset + velocity * 1.5F, 0), 256 * static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5))); + + startOffset = xOffsetNext; + + positions.clear(); + oldPosition = {0}; + } + else { + xOffset = startOffset + (static_cast(startPosition.px) - static_cast(currPosition.px)); + xOffset = std::min(std::max(xOffset, 0), 256 * static_cast(std::ceil(((!m_editableOnly) ? Title::g_titles.size() : EditorConfigParser::g_editableTitles.size()) / 2.0F - 5))); + xOffsetNext = xOffset; + } + + if (oldPosition.px != 0x00) { + s32 pos = static_cast(oldPosition.px) - static_cast(currPosition.px); + if (std::abs(pos) < 400) + positions.push_back(pos); + } + + if (positions.size() > 10) + positions.erase(positions.begin()); + + oldPosition = currPosition; +} + +void GuiMain::updateEditableTitlesList() { + EditorConfigParser::g_editableTitles.clear(); + EditorConfigParser::g_betaTitles.clear(); + + for (auto title : Title::g_titles) { + if (EditorConfigParser::hasConfig(title.first) == 0) { + EditorConfigParser::g_editableTitles.insert({title.first, true}); + } + } +} diff --git a/source/guis/gui_tx_warning.cpp b/source/guis/gui_tx_warning.cpp index 65fc6fd3..d06dc127 100644 --- a/source/guis/gui_tx_warning.cpp +++ b/source/guis/gui_tx_warning.cpp @@ -1,50 +1,50 @@ -#include "guis/gui_tx_warning.hpp" - -#include "helpers/config.hpp" - -GuiTXWarning::GuiTXWarning() : Gui() { - Config::getConfig()->hideSX = false; -} - -GuiTXWarning::~GuiTXWarning() { - -} - -void GuiTXWarning::update() { - Gui::update(); -} - -void GuiTXWarning::draw() { - Gui::beginDraw(); - - Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0xC5, 0x39, 0x29, 0xFF)); - Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, COLOR_WHITE, "\uE150", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, COLOR_WHITE, "EdiZon detected that you're running the 'SX OS' CFW. Please note that this CFW has erroneously\n implemented services that can cause unexpected failures, corruption of save data\n or backups, the editor failing to load save files or configs, RAM editing not being\n supported and other issues. For the safety of your Switch, use a free open\n source CFW instead. \n To continue anyway press \uE0E0, otherwise press \uE0E1 to exit.", ALIGNED_CENTER); - - Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 + 250, COLOR_WHITE, "\uE070 Don't show this warning anymore", ALIGNED_CENTER); - - if (!Config::getConfig()->hideSX) - Gui::drawRectangle(Gui::g_framebuffer_width / 2 - 228, Gui::g_framebuffer_height / 2 + 258, 14, 16, Gui::makeColor(0xC5, 0x39, 0x29, 0xFF)); - - Gui::endDraw(); -} - -void GuiTXWarning::onInput(u32 kdown) { - if (kdown & KEY_B) - Gui::g_requestExit = true; - - if (kdown & KEY_A) - Gui::g_nextGui = GUI_MAIN; -} - -void GuiTXWarning::onTouch(touchPosition &touch) { - if (touch.px > 400 && touch.px < 900 && touch.py > 600 && touch.py < 660) { - Config::getConfig()->hideSX = !Config::getConfig()->hideSX; - Config::writeConfig(); - } -} - -void GuiTXWarning::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} +#include "guis/gui_tx_warning.hpp" + +#include "helpers/config.hpp" + +GuiTXWarning::GuiTXWarning() : Gui() { + Config::getConfig()->hideSX = false; +} + +GuiTXWarning::~GuiTXWarning() { + +} + +void GuiTXWarning::update() { + Gui::update(); +} + +void GuiTXWarning::draw() { + Gui::beginDraw(); + + Gui::drawRectangle(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, Gui::makeColor(0xC5, 0x39, 0x29, 0xFF)); + Gui::drawTextAligned(fontHuge, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 100, COLOR_WHITE, "\uE150", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2, COLOR_WHITE, "EdiZon detected that you're running the 'SX OS' CFW. Please note that this CFW has erroneously\n implemented services that can cause unexpected failures, corruption of save data\n or backups, the editor failing to load save files or configs, RAM editing not being\n supported and other issues. For the safety of your Switch, use a free open\n source CFW instead. \n To continue anyway press \uE0E0, otherwise press \uE0E1 to exit.", ALIGNED_CENTER); + + Gui::drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 + 250, COLOR_WHITE, "\uE070 Don't show this warning anymore", ALIGNED_CENTER); + + if (!Config::getConfig()->hideSX) + Gui::drawRectangle(Gui::g_framebuffer_width / 2 - 228, Gui::g_framebuffer_height / 2 + 258, 14, 16, Gui::makeColor(0xC5, 0x39, 0x29, 0xFF)); + + Gui::endDraw(); +} + +void GuiTXWarning::onInput(u32 kdown) { + if (kdown & KEY_B) + Gui::g_requestExit = true; + + if (kdown & KEY_A) + Gui::g_nextGui = GUI_MAIN; +} + +void GuiTXWarning::onTouch(touchPosition &touch) { + if (touch.px > 400 && touch.px < 900 && touch.py > 600 && touch.py < 660) { + Config::getConfig()->hideSX = !Config::getConfig()->hideSX; + Config::writeConfig(); + } +} + +void GuiTXWarning::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} diff --git a/source/helpers/account.cpp b/source/helpers/account.cpp index b479031f..60c41406 100644 --- a/source/helpers/account.cpp +++ b/source/helpers/account.cpp @@ -1,59 +1,59 @@ -#include "helpers/account.hpp" - -#include "guis/gui.hpp" - -#include -#include - -extern "C" { - #include "nanojpeg.h" -} - -Account::Account(u128 userID) : m_userID(userID) { - if (R_FAILED(accountGetProfile(&m_profile, userID))) return; - - if (!serviceIsActive(&m_profile.s)) return; - - if (R_FAILED(accountProfileGet(&m_profile, &m_userData, &m_profileBase))) return; - if (R_FAILED(accountProfileGetImageSize(&m_profile, &m_profileImageSize))) return; - - m_userName = std::string(m_profileBase.username); - - std::vector buffer(m_profileImageSize); - u8 *decodedBuffer; - size_t imageSize = 0; - - if (R_FAILED(accountProfileLoadImage(&m_profile, &buffer[0], m_profileImageSize, &imageSize))) return; - - njInit(); - njDecode(&buffer[0], imageSize); - - m_profileImage.reserve(128 * 128 * 3); - decodedBuffer = njGetImage(); - Gui::resizeImage(decodedBuffer, &m_profileImage[0], 256, 256, 128, 128); - - njDone(); - - accountProfileClose(&m_profile); - - m_isInitialized = true; -} - -Account::~Account() { -} - -u128 Account::getUserID() { - return m_userID; -} - -std::string Account::getUserName() { - return m_userName; -} - -u8* Account::getProfileImage() { - return &m_profileImage[0]; -} - -bool Account::isInitialized() { - return m_isInitialized; +#include "helpers/account.hpp" + +#include "guis/gui.hpp" + +#include +#include + +extern "C" { + #include "nanojpeg.h" +} + +Account::Account(u128 userID) : m_userID(userID) { + if (R_FAILED(accountGetProfile(&m_profile, userID))) return; + + if (!serviceIsActive(&m_profile.s)) return; + + if (R_FAILED(accountProfileGet(&m_profile, &m_userData, &m_profileBase))) return; + if (R_FAILED(accountProfileGetImageSize(&m_profile, &m_profileImageSize))) return; + + m_userName = std::string(m_profileBase.username); + + std::vector buffer(m_profileImageSize); + u8 *decodedBuffer; + size_t imageSize = 0; + + if (R_FAILED(accountProfileLoadImage(&m_profile, &buffer[0], m_profileImageSize, &imageSize))) return; + + njInit(); + njDecode(&buffer[0], imageSize); + + m_profileImage.reserve(128 * 128 * 3); + decodedBuffer = njGetImage(); + Gui::resizeImage(decodedBuffer, &m_profileImage[0], 256, 256, 128, 128); + + njDone(); + + accountProfileClose(&m_profile); + + m_isInitialized = true; +} + +Account::~Account() { +} + +u128 Account::getUserID() { + return m_userID; +} + +std::string Account::getUserName() { + return m_userName; +} + +u8* Account::getProfileImage() { + return &m_profileImage[0]; +} + +bool Account::isInitialized() { + return m_isInitialized; } \ No newline at end of file diff --git a/source/helpers/config.cpp b/source/helpers/config.cpp index 6a397a68..38d71b40 100644 --- a/source/helpers/config.cpp +++ b/source/helpers/config.cpp @@ -1,32 +1,32 @@ -#include "helpers/config.hpp" - -static Config::config_data_t configData; - -void Config::readConfig() { -memset(&configData, 0x00, sizeof(config_data_t)); - -if (access(CONFIG_PATH, F_OK) == 0) { - FILE *configFile = fopen(CONFIG_PATH, "r+"); - fread(&configData, 1, sizeof(config_data_t), configFile); - fclose(configFile); - - if (strcmp(configData.magic, "EDZNCFG") != 0) { - memset(&configData, 0x00, sizeof(config_data_t)); - Config::writeConfig(); - } -} else - Config::writeConfig(); -} - -void Config::writeConfig() { -FILE *configFile = fopen(CONFIG_PATH, "wr"); - -memcpy(configData.magic, "EDZNCFG", 8); -fwrite(&configData, 1, sizeof(config_data_t), configFile); - -fclose(configFile); -} - -Config::config_data_t* Config::getConfig() { -return &configData; +#include "helpers/config.hpp" + +static Config::config_data_t configData; + +void Config::readConfig() { +memset(&configData, 0x00, sizeof(config_data_t)); + +if (access(CONFIG_PATH, F_OK) == 0) { + FILE *configFile = fopen(CONFIG_PATH, "r+"); + fread(&configData, 1, sizeof(config_data_t), configFile); + fclose(configFile); + + if (strcmp(configData.magic, "EDZNCFG") != 0) { + memset(&configData, 0x00, sizeof(config_data_t)); + Config::writeConfig(); + } +} else + Config::writeConfig(); +} + +void Config::writeConfig() { +FILE *configFile = fopen(CONFIG_PATH, "wr"); + +memcpy(configData.magic, "EDZNCFG", 8); +fwrite(&configData, 1, sizeof(config_data_t), configFile); + +fclose(configFile); +} + +Config::config_data_t* Config::getConfig() { +return &configData; } \ No newline at end of file diff --git a/source/helpers/debugger.cpp b/source/helpers/debugger.cpp index f05fbd7d..f44cbc10 100644 --- a/source/helpers/debugger.cpp +++ b/source/helpers/debugger.cpp @@ -1,58 +1,58 @@ -#include "helpers/debugger.hpp" - -#include "helpers/dmntcht.h" - -Debugger::Debugger() { - pmdmntInitialize(); - pminfoInitialize(); - - m_pid = 0; - m_tid = 0; - - pmdmntGetApplicationPid(&m_pid); - pminfoGetTitleId(&m_tid, m_pid); -} - -Debugger::~Debugger() { - pminfoExit(); - pmdmntExit(); -} - -Result Debugger::attachToProcess() { - return dmntchtForceOpenCheatProcess(); -} - -u64 Debugger::getRunningApplicationTID() { - return m_tid; -} - -u64 Debugger::getRunningApplicationPID() { - return m_pid; -} - -u64 Debugger::peekMemory(u64 address) { - u64 out; - dmntchtReadCheatProcessMemory(address, &out, sizeof(u64)); - - return out; -} - -void Debugger::pokeMemory(size_t varSize, u64 address, u64 value) { - dmntchtWriteCheatProcessMemory(address, &value, varSize); -} - -void Debugger::readMemory(void *buffer, size_t bufferSize, u64 address) { - dmntchtReadCheatProcessMemory(address, buffer, bufferSize); -} - -void Debugger::writeMemory(void *buffer, size_t bufferSize, u64 address) { - dmntchtWriteCheatProcessMemory(address, buffer, bufferSize); -} - -MemoryInfo Debugger::queryMemory(u64 address) { - MemoryInfo memInfo = { 0 }; - - dmntchtQueryCheatProcessMemory(&memInfo, address); - - return memInfo; +#include "helpers/debugger.hpp" + +#include "helpers/dmntcht.h" + +Debugger::Debugger() { + pmdmntInitialize(); + pminfoInitialize(); + + m_pid = 0; + m_tid = 0; + + pmdmntGetApplicationPid(&m_pid); + pminfoGetTitleId(&m_tid, m_pid); +} + +Debugger::~Debugger() { + pminfoExit(); + pmdmntExit(); +} + +Result Debugger::attachToProcess() { + return dmntchtForceOpenCheatProcess(); +} + +u64 Debugger::getRunningApplicationTID() { + return m_tid; +} + +u64 Debugger::getRunningApplicationPID() { + return m_pid; +} + +u64 Debugger::peekMemory(u64 address) { + u64 out; + dmntchtReadCheatProcessMemory(address, &out, sizeof(u64)); + + return out; +} + +void Debugger::pokeMemory(size_t varSize, u64 address, u64 value) { + dmntchtWriteCheatProcessMemory(address, &value, varSize); +} + +void Debugger::readMemory(void *buffer, size_t bufferSize, u64 address) { + dmntchtReadCheatProcessMemory(address, buffer, bufferSize); +} + +void Debugger::writeMemory(void *buffer, size_t bufferSize, u64 address) { + dmntchtWriteCheatProcessMemory(address, buffer, bufferSize); +} + +MemoryInfo Debugger::queryMemory(u64 address) { + MemoryInfo memInfo = { 0 }; + + dmntchtQueryCheatProcessMemory(&memInfo, address); + + return memInfo; } \ No newline at end of file diff --git a/source/helpers/dmntcht.c b/source/helpers/dmntcht.c index b5c4a84e..0b03ae58 100644 --- a/source/helpers/dmntcht.c +++ b/source/helpers/dmntcht.c @@ -1,632 +1,632 @@ -#include "helpers/dmntcht.h" - -static Service g_dmntchtService; -static u64 g_refCnt; - -static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count); -static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count); - -Result dmntchtInitialize(void) { - atomicIncrement64(&g_refCnt); - - if (serviceIsActive(&g_dmntchtService)) { - return 0; - } - - return smGetService(&g_dmntchtService, "dmnt:cht"); -} - -void dmntchtExit(void) { - if (atomicIncrement64(&g_refCnt) == 0) { - serviceClose(&g_dmntchtService); - } -} - -Service* dmntchtGetServiceSession(void) { - return &g_dmntchtService; -} - -Result dmntchtHasCheatProcess(bool *out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65000; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - bool out; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out) *out = resp->out; - } - } - - return rc; -} - -Result dmntchtGetCheatProcessEvent(Event *event) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65001; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - eventLoadRemote(event, r.Handles[0], true); - } - } - - return rc; -} - -Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65002; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - DmntCheatProcessMetadata metadata; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out_metadata) *out_metadata = resp->metadata; - } - } - - return rc; -} - -Result dmntchtForceOpenCheatProcess(void) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65003; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - -static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = cmd_id; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - u64 count; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - *out_count = resp->count; - } - - return rc; -} - -static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, buffer, buffer_size, 0); - - struct { - u64 magic; - u64 cmd_id; - u64 offset; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = cmd_id; - raw->offset = offset; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - u64 count; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out_count) *out_count = resp->count; - } - } - - return rc; -} - -Result dmntchtGetCheatProcessMappingCount(u64 *out_count) { - return _dmntchtGetCount(65100, out_count); -} - -Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) { - return _dmntchtGetEntries(65101, buffer, sizeof(*buffer) * max_count, offset, out_count); -} - -Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, buffer, size, 0); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - u64 size; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65102; - raw->address = address; - raw->size = size; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - -Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) { - IpcCommand c; - ipcInitialize(&c); - ipcAddSendBuffer(&c, buffer, size, 0); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - u64 size; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65103; - raw->address = address; - raw->size = size; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - -Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){ - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65104; - raw->address = address; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - MemoryInfo mem_info; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (mem_info) *mem_info = resp->mem_info; - } - } - - return rc; -} - -Result dmntchtGetCheatCount(u64 *out_count) { - return _dmntchtGetCount(65200, out_count); -} - -Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { - return _dmntchtGetEntries(65201, buffer, sizeof(*buffer) * max_count, offset, out_count); -} - -Result dmntchtGetCheatById(DmntCheatEntry *buffer, u32 cheat_id) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, buffer, sizeof(*buffer), 0); - - struct { - u64 magic; - u64 cmd_id; - u32 cheat_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65202; - raw->cheat_id = cheat_id; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - -Result dmntchtToggleCheat(u32 cheat_id) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 cheat_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65203; - raw->cheat_id = cheat_id; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - -Result dmntchtAddCheat(DmntCheatDefinition *buffer, bool enabled, u32 *out_cheat_id) { - IpcCommand c; - ipcInitialize(&c); - ipcAddSendBuffer(&c, buffer, sizeof(*buffer), 0); - - struct { - u64 magic; - u64 cmd_id; - u8 enabled; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65204; - raw->enabled = enabled; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - u32 cheat_id; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out_cheat_id) *out_cheat_id = resp->cheat_id; - } - } - - return rc; -} - -Result dmntchtRemoveCheat(u32 cheat_id) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 cheat_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65205; - raw->cheat_id = cheat_id; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; -} - - -Result dmntchtGetFrozenAddressCount(u64 *out_count) { - return _dmntchtGetCount(65300, out_count); -} - -Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { - return _dmntchtGetEntries(65301, buffer, sizeof(*buffer) * max_count, offset, out_count); -} - -Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65302; - raw->address = address; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - DmntFrozenAddressEntry entry; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out) *out = resp->entry; - } - } - - return rc; -} - -Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - u64 width; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65303; - raw->address = address; - raw->width = width; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - u64 value; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - if (out_value) *out_value = resp->value; - } - } - - return rc; -} - -Result dmntchtDisableFrozenAddress(u64 address) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 address; - } *raw; - - raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65304; - raw->address = address; - - Result rc = serviceIpcDispatch(&g_dmntchtService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - u64 value; - } *resp; - - serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - } - - return rc; +#include "helpers/dmntcht.h" + +static Service g_dmntchtService; +static u64 g_refCnt; + +static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count); +static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count); + +Result dmntchtInitialize(void) { + atomicIncrement64(&g_refCnt); + + if (serviceIsActive(&g_dmntchtService)) { + return 0; + } + + return smGetService(&g_dmntchtService, "dmnt:cht"); +} + +void dmntchtExit(void) { + if (atomicIncrement64(&g_refCnt) == 0) { + serviceClose(&g_dmntchtService); + } +} + +Service* dmntchtGetServiceSession(void) { + return &g_dmntchtService; +} + +Result dmntchtHasCheatProcess(bool *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + bool out; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out) *out = resp->out; + } + } + + return rc; +} + +Result dmntchtGetCheatProcessEvent(Event *event) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65001; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + eventLoadRemote(event, r.Handles[0], true); + } + } + + return rc; +} + +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65002; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + DmntCheatProcessMetadata metadata; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_metadata) *out_metadata = resp->metadata; + } + } + + return rc; +} + +Result dmntchtForceOpenCheatProcess(void) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65003; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _dmntchtGetCount(u64 cmd_id, u64 *out_count) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 count; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + *out_count = resp->count; + } + + return rc; +} + +static Result _dmntchtGetEntries(u64 cmd_id, void *buffer, u64 buffer_size, u64 offset, u64 *out_count) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, buffer_size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 offset; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->offset = offset; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 count; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_count) *out_count = resp->count; + } + } + + return rc; +} + +Result dmntchtGetCheatProcessMappingCount(u64 *out_count) { + return _dmntchtGetCount(65100, out_count); +} + +Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65101, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65102; + raw->address = address; + raw->size = size; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65103; + raw->address = address; + raw->size = size; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){ + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65104; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + MemoryInfo mem_info; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (mem_info) *mem_info = resp->mem_info; + } + } + + return rc; +} + +Result dmntchtGetCheatCount(u64 *out_count) { + return _dmntchtGetCount(65200, out_count); +} + +Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65201, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtGetCheatById(DmntCheatEntry *buffer, u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buffer, sizeof(*buffer), 0); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65202; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtToggleCheat(u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65203; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result dmntchtAddCheat(DmntCheatDefinition *buffer, bool enabled, u32 *out_cheat_id) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buffer, sizeof(*buffer), 0); + + struct { + u64 magic; + u64 cmd_id; + u8 enabled; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65204; + raw->enabled = enabled; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u32 cheat_id; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_cheat_id) *out_cheat_id = resp->cheat_id; + } + } + + return rc; +} + +Result dmntchtRemoveCheat(u32 cheat_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 cheat_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65205; + raw->cheat_id = cheat_id; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + + +Result dmntchtGetFrozenAddressCount(u64 *out_count) { + return _dmntchtGetCount(65300, out_count); +} + +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { + return _dmntchtGetEntries(65301, buffer, sizeof(*buffer) * max_count, offset, out_count); +} + +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65302; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + DmntFrozenAddressEntry entry; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out) *out = resp->entry; + } + } + + return rc; +} + +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + u64 width; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65303; + raw->address = address; + raw->width = width; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 value; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc)) { + if (out_value) *out_value = resp->value; + } + } + + return rc; +} + +Result dmntchtDisableFrozenAddress(u64 address) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntchtService, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65304; + raw->address = address; + + Result rc = serviceIpcDispatch(&g_dmntchtService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 value; + } *resp; + + serviceIpcParse(&g_dmntchtService, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; } \ No newline at end of file diff --git a/source/helpers/editor_config_parser.cpp b/source/helpers/editor_config_parser.cpp index 01ecfe4f..8385dada 100644 --- a/source/helpers/editor_config_parser.cpp +++ b/source/helpers/editor_config_parser.cpp @@ -1,193 +1,193 @@ -#include "helpers/editor_config_parser.hpp" -#include "helpers/title.hpp" - -#include "widgets/widget_switch.hpp" -#include "widgets/widget_value.hpp" -#include "widgets/widget_list.hpp" -#include "widgets/widget_string.hpp" -#include "widgets/widget_comment.hpp" -#include "widgets/widget_button.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scripting/lua_interpreter.hpp" -#include "scripting/python_interpreter.hpp" - -s8 EditorConfigParser::hasConfig(u64 titleId) { - std::stringstream path; - path << CONFIG_ROOT << std::setfill('0') << std::setw(sizeof(u64) * 2) << std::uppercase << std::hex << titleId << ".json"; - - return EditorConfigParser::loadConfigFile(titleId, path.str(), nullptr); -} - -s8 EditorConfigParser::loadConfigFile(u64 titleId, std::string filepath, Interpreter **interpreter) { - std::ifstream file(filepath.c_str()); - if (file.fail()) - return 1; - - try { - file >> EditorConfigParser::m_configFile; - } catch (json::parse_error& e) { - printf("Failed to parse JSON file.\n"); - return 2; - } - - if (m_useInsteadTries++ > 5) { - m_useInsteadTries = 0; - return 4; - } - - if (EditorConfigParser::m_configFile.find("useInstead") != EditorConfigParser::m_configFile.end()) { - std::stringstream path; - path << CONFIG_ROOT << EditorConfigParser::m_configFile["useInstead"].get(); - return EditorConfigParser::loadConfigFile(titleId, path.str(), interpreter); - } - - m_useInsteadTries = 0; - - if (EditorConfigParser::m_configFile.find("author") != EditorConfigParser::m_configFile.end()) - EditorConfigParser::g_currConfigAuthor = EditorConfigParser::m_configFile["author"]; - - if (EditorConfigParser::m_configFile.find("beta") != EditorConfigParser::m_configFile.end()) - EditorConfigParser::g_betaTitles.insert({titleId, EditorConfigParser::m_configFile["beta"]}); - - if (interpreter != nullptr) { - if (EditorConfigParser::m_configFile.find("scriptLanguage") != EditorConfigParser::m_configFile.end()) { - std::string language = EditorConfigParser::m_configFile["scriptLanguage"]; - - std::transform(language.begin(), language.end(), language.begin(), ::tolower); - - if (language == "lua") *interpreter = new LuaInterpreter(); - else if (language == "py" || language == "python") *interpreter = new PythonInterpreter(); - else return 2; - } else return 2; - } - - if (EditorConfigParser::m_configFile.find("all") == EditorConfigParser::m_configFile.end()) { - for (auto it : EditorConfigParser::m_configFile.items()) { - if (it.key().find(Title::g_titles[titleId]->getTitleVersion()) != std::string::npos) { - EditorConfigParser::m_configFile = EditorConfigParser::m_configFile[it.key()]; - - if (EditorConfigParser::m_configFile == nullptr || !EditorConfigParser::m_configFile.is_array()) { - EditorConfigParser::g_betaTitles.erase(titleId); - return 2; - } - - return 0; - } - } - - EditorConfigParser::g_betaTitles.erase(titleId); - return 3; - } else { - EditorConfigParser::m_configFile = EditorConfigParser::m_configFile["all"]; - - if (!EditorConfigParser::m_configFile.is_array()) { - EditorConfigParser::g_betaTitles.erase(titleId); - return 2; - } - - return 0; - } -} - -void EditorConfigParser::createWidgets(WidgetItems &widgets, Interpreter &interpreter, u8 configIndex) { - std::set tempCategories; - - if (EditorConfigParser::m_configFile == nullptr) return; - - if (!EditorConfigParser::m_configFile.is_array()) return; - - for (auto item : EditorConfigParser::m_configFile[configIndex]["items"]) { - bool isDummy = false; - std::string tooltip = ""; - - if (item["name"] == nullptr || item["category"] == nullptr || item["intArgs"] == nullptr || item["strArgs"] == nullptr) continue; - - if (item["dummy"] != nullptr) - isDummy = item["dummy"].get(); - - if (item["tooltip"] != nullptr) - tooltip = item["tooltip"]; - - auto itemWidget = item["widget"]; - if (itemWidget == nullptr) continue; - if (itemWidget["type"] == nullptr) continue; - - if (itemWidget["type"] == "int") { - if (itemWidget["minValue"] == nullptr || itemWidget["maxValue"] == nullptr) continue; - if (itemWidget["minValue"] >= itemWidget["maxValue"]) continue; - widgets[item["category"]].push_back({ item["name"], - new WidgetValue(&interpreter, isDummy, tooltip, - EditorConfigParser::getOptionalValue(itemWidget, "readEquation", "value"), - EditorConfigParser::getOptionalValue(itemWidget, "writeEquation", "value"), - itemWidget["minValue"], itemWidget["maxValue"], - EditorConfigParser::getOptionalValue(itemWidget, "stepSize", 1)) }); - } - else if (itemWidget["type"] == "bool") { - if (itemWidget["onValue"] == nullptr || itemWidget["offValue"] == nullptr) continue; - if (itemWidget["onValue"] == itemWidget["offValue"]) continue; - if(itemWidget["onValue"].is_number() && itemWidget["offValue"].is_number()) { - widgets[item["category"]].push_back({ item["name"], - new WidgetSwitch(&interpreter, isDummy, tooltip, itemWidget["onValue"].get(), itemWidget["offValue"].get()) }); - } - else if(itemWidget["onValue"].is_string() && itemWidget["offValue"].is_string()) - widgets[item["category"]].push_back({ item["name"], - new WidgetSwitch(&interpreter, isDummy, tooltip, itemWidget["onValue"].get(), itemWidget["offValue"].get()) }); - } - else if (itemWidget["type"] == "list") { - if (itemWidget["listItemNames"] == nullptr || itemWidget["listItemValues"] == nullptr) continue; - - if (itemWidget["listItemValues"][0].is_number()) { - widgets[item["category"]].push_back({ item["name"], - new WidgetList(&interpreter, isDummy, tooltip, itemWidget["listItemNames"], itemWidget["listItemValues"].get>()) }); - } - else if (itemWidget["listItemValues"][0].is_string()) - widgets[item["category"]].push_back({ item["name"], - new WidgetList(&interpreter, isDummy, tooltip, itemWidget["listItemNames"], itemWidget["listItemValues"].get>()) }); - } - else if (itemWidget["type"] == "string") { - if (itemWidget["minLength"] == nullptr || itemWidget["maxLength"] == nullptr) continue; - - if (itemWidget["minLength"].is_number() && itemWidget["maxLength"].is_number()) { - widgets[item["category"]].push_back({ item["name"], - new WidgetString(&interpreter, isDummy, tooltip, itemWidget["minLength"].get(), itemWidget["maxLength"].get()) }); - } - } - else if (itemWidget["type"] == "comment") { - if (itemWidget["comment"] == nullptr) continue; - - if (itemWidget["comment"].is_string()) { - widgets[item["category"]].push_back({ item["name"], - new WidgetComment(&interpreter, tooltip, itemWidget["comment"].get()) }); - } - } - else if (itemWidget["type"] == "button") { - if (itemWidget["function"] == nullptr) continue; - - if (itemWidget["function"].is_string()) { - widgets[item["category"]].push_back({ item["name"], - new WidgetButton(&interpreter, tooltip, itemWidget["function"].get()) }); - } - } - - widgets[item["category"]].back().widget->setLuaArgs(item["intArgs"], item["strArgs"]); - - tempCategories.insert(item["category"].get());; - Widget::g_selectedRow = CATEGORIES; - } - - Widget::g_categories.clear(); - std::copy(tempCategories.begin(), tempCategories.end(), std::back_inserter(Widget::g_categories)); - Widget::g_selectedCategory = Widget::g_categories[0]; - - for (auto category : tempCategories) - Widget::g_widgetPageCnt[category] = ceil(widgets[category].size() / WIDGETS_PER_PAGE); -} +#include "helpers/editor_config_parser.hpp" +#include "helpers/title.hpp" + +#include "widgets/widget_switch.hpp" +#include "widgets/widget_value.hpp" +#include "widgets/widget_list.hpp" +#include "widgets/widget_string.hpp" +#include "widgets/widget_comment.hpp" +#include "widgets/widget_button.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scripting/lua_interpreter.hpp" +#include "scripting/python_interpreter.hpp" + +s8 EditorConfigParser::hasConfig(u64 titleId) { + std::stringstream path; + path << CONFIG_ROOT << std::setfill('0') << std::setw(sizeof(u64) * 2) << std::uppercase << std::hex << titleId << ".json"; + + return EditorConfigParser::loadConfigFile(titleId, path.str(), nullptr); +} + +s8 EditorConfigParser::loadConfigFile(u64 titleId, std::string filepath, Interpreter **interpreter) { + std::ifstream file(filepath.c_str()); + if (file.fail()) + return 1; + + try { + file >> EditorConfigParser::m_configFile; + } catch (json::parse_error& e) { + printf("Failed to parse JSON file.\n"); + return 2; + } + + if (m_useInsteadTries++ > 5) { + m_useInsteadTries = 0; + return 4; + } + + if (EditorConfigParser::m_configFile.find("useInstead") != EditorConfigParser::m_configFile.end()) { + std::stringstream path; + path << CONFIG_ROOT << EditorConfigParser::m_configFile["useInstead"].get(); + return EditorConfigParser::loadConfigFile(titleId, path.str(), interpreter); + } + + m_useInsteadTries = 0; + + if (EditorConfigParser::m_configFile.find("author") != EditorConfigParser::m_configFile.end()) + EditorConfigParser::g_currConfigAuthor = EditorConfigParser::m_configFile["author"]; + + if (EditorConfigParser::m_configFile.find("beta") != EditorConfigParser::m_configFile.end()) + EditorConfigParser::g_betaTitles.insert({titleId, EditorConfigParser::m_configFile["beta"]}); + + if (interpreter != nullptr) { + if (EditorConfigParser::m_configFile.find("scriptLanguage") != EditorConfigParser::m_configFile.end()) { + std::string language = EditorConfigParser::m_configFile["scriptLanguage"]; + + std::transform(language.begin(), language.end(), language.begin(), ::tolower); + + if (language == "lua") *interpreter = new LuaInterpreter(); + else if (language == "py" || language == "python") *interpreter = new PythonInterpreter(); + else return 2; + } else return 2; + } + + if (EditorConfigParser::m_configFile.find("all") == EditorConfigParser::m_configFile.end()) { + for (auto it : EditorConfigParser::m_configFile.items()) { + if (it.key().find(Title::g_titles[titleId]->getTitleVersion()) != std::string::npos) { + EditorConfigParser::m_configFile = EditorConfigParser::m_configFile[it.key()]; + + if (EditorConfigParser::m_configFile == nullptr || !EditorConfigParser::m_configFile.is_array()) { + EditorConfigParser::g_betaTitles.erase(titleId); + return 2; + } + + return 0; + } + } + + EditorConfigParser::g_betaTitles.erase(titleId); + return 3; + } else { + EditorConfigParser::m_configFile = EditorConfigParser::m_configFile["all"]; + + if (!EditorConfigParser::m_configFile.is_array()) { + EditorConfigParser::g_betaTitles.erase(titleId); + return 2; + } + + return 0; + } +} + +void EditorConfigParser::createWidgets(WidgetItems &widgets, Interpreter &interpreter, u8 configIndex) { + std::set tempCategories; + + if (EditorConfigParser::m_configFile == nullptr) return; + + if (!EditorConfigParser::m_configFile.is_array()) return; + + for (auto item : EditorConfigParser::m_configFile[configIndex]["items"]) { + bool isDummy = false; + std::string tooltip = ""; + + if (item["name"] == nullptr || item["category"] == nullptr || item["intArgs"] == nullptr || item["strArgs"] == nullptr) continue; + + if (item["dummy"] != nullptr) + isDummy = item["dummy"].get(); + + if (item["tooltip"] != nullptr) + tooltip = item["tooltip"]; + + auto itemWidget = item["widget"]; + if (itemWidget == nullptr) continue; + if (itemWidget["type"] == nullptr) continue; + + if (itemWidget["type"] == "int") { + if (itemWidget["minValue"] == nullptr || itemWidget["maxValue"] == nullptr) continue; + if (itemWidget["minValue"] >= itemWidget["maxValue"]) continue; + widgets[item["category"]].push_back({ item["name"], + new WidgetValue(&interpreter, isDummy, tooltip, + EditorConfigParser::getOptionalValue(itemWidget, "readEquation", "value"), + EditorConfigParser::getOptionalValue(itemWidget, "writeEquation", "value"), + itemWidget["minValue"], itemWidget["maxValue"], + EditorConfigParser::getOptionalValue(itemWidget, "stepSize", 1)) }); + } + else if (itemWidget["type"] == "bool") { + if (itemWidget["onValue"] == nullptr || itemWidget["offValue"] == nullptr) continue; + if (itemWidget["onValue"] == itemWidget["offValue"]) continue; + if(itemWidget["onValue"].is_number() && itemWidget["offValue"].is_number()) { + widgets[item["category"]].push_back({ item["name"], + new WidgetSwitch(&interpreter, isDummy, tooltip, itemWidget["onValue"].get(), itemWidget["offValue"].get()) }); + } + else if(itemWidget["onValue"].is_string() && itemWidget["offValue"].is_string()) + widgets[item["category"]].push_back({ item["name"], + new WidgetSwitch(&interpreter, isDummy, tooltip, itemWidget["onValue"].get(), itemWidget["offValue"].get()) }); + } + else if (itemWidget["type"] == "list") { + if (itemWidget["listItemNames"] == nullptr || itemWidget["listItemValues"] == nullptr) continue; + + if (itemWidget["listItemValues"][0].is_number()) { + widgets[item["category"]].push_back({ item["name"], + new WidgetList(&interpreter, isDummy, tooltip, itemWidget["listItemNames"], itemWidget["listItemValues"].get>()) }); + } + else if (itemWidget["listItemValues"][0].is_string()) + widgets[item["category"]].push_back({ item["name"], + new WidgetList(&interpreter, isDummy, tooltip, itemWidget["listItemNames"], itemWidget["listItemValues"].get>()) }); + } + else if (itemWidget["type"] == "string") { + if (itemWidget["minLength"] == nullptr || itemWidget["maxLength"] == nullptr) continue; + + if (itemWidget["minLength"].is_number() && itemWidget["maxLength"].is_number()) { + widgets[item["category"]].push_back({ item["name"], + new WidgetString(&interpreter, isDummy, tooltip, itemWidget["minLength"].get(), itemWidget["maxLength"].get()) }); + } + } + else if (itemWidget["type"] == "comment") { + if (itemWidget["comment"] == nullptr) continue; + + if (itemWidget["comment"].is_string()) { + widgets[item["category"]].push_back({ item["name"], + new WidgetComment(&interpreter, tooltip, itemWidget["comment"].get()) }); + } + } + else if (itemWidget["type"] == "button") { + if (itemWidget["function"] == nullptr) continue; + + if (itemWidget["function"].is_string()) { + widgets[item["category"]].push_back({ item["name"], + new WidgetButton(&interpreter, tooltip, itemWidget["function"].get()) }); + } + } + + widgets[item["category"]].back().widget->setLuaArgs(item["intArgs"], item["strArgs"]); + + tempCategories.insert(item["category"].get());; + Widget::g_selectedRow = CATEGORIES; + } + + Widget::g_categories.clear(); + std::copy(tempCategories.begin(), tempCategories.end(), std::back_inserter(Widget::g_categories)); + Widget::g_selectedCategory = Widget::g_categories[0]; + + for (auto category : tempCategories) + Widget::g_widgetPageCnt[category] = ceil(widgets[category].size() / WIDGETS_PER_PAGE); +} diff --git a/source/helpers/encoding.cpp b/source/helpers/encoding.cpp index 0323d0a2..4906fd68 100644 --- a/source/helpers/encoding.cpp +++ b/source/helpers/encoding.cpp @@ -1,125 +1,125 @@ -#include "helpers/encoding.hpp" - -std::vector Encoding::uft16leToUtf8(u8 *data, size_t length) { - std::vector utf16Chars(length / 2); - std::vector utf8Chars; - utf8Chars.reserve(length / 2); - - for (u32 i = 0; i < length; i += 2) { - u16 c = data[i] | data[i + 1] << 8; - utf16Chars[i / 2] = c; - } - - for (u32 character = 0; character < length / 2; character++) { - u16 currChar = utf16Chars[character]; - - if (currChar <= 0x007F) { - utf8Chars.push_back(currChar & 0xFF); - } - else if (currChar <= 0x07FF) { - utf8Chars.push_back(0xC0 | ((currChar & 0x7C0) >> 6)); - utf8Chars.push_back(0x80 | (currChar & 0x3F)); - } - else { - utf8Chars.push_back(0xE0 | ((currChar & 0xF000) >> 12)); - utf8Chars.push_back(0x80 | ((currChar & 0xFC0) >> 6)); - utf8Chars.push_back(0x80 | (currChar & 0x3F)); - } - } - - utf8Chars.push_back(0x00); - utf8Chars.shrink_to_fit(); - - return utf8Chars; -} - -std::vector Encoding::uft16beToUtf8(u8 *data, size_t length) { - std::vector utf16Chars(length / 2); - std::vector utf8Chars; - utf8Chars.reserve(length / 2); - - for (u32 i = 0; i < length; i += 2) { - u16 c = data[i + 1] | data[i] << 8; - utf16Chars[i / 2] = c; - } - - for (u32 character = 0; character < length / 2; character++) { - u16 currChar = utf16Chars[character]; - - if (currChar <= 0x007F) { - utf8Chars.push_back(currChar & 0xFF); - } - else if (currChar <= 0x07FF) { - utf8Chars.push_back(0xC0 | ((currChar & 0x7C0) >> 6)); - utf8Chars.push_back(0x80 | (currChar & 0x3F)); - } - else { - utf8Chars.push_back(0xE0 | ((currChar & 0xF000) >> 12)); - utf8Chars.push_back(0x80 | ((currChar & 0xFC0) >> 6)); - utf8Chars.push_back(0x80 | (currChar & 0x3F)); - } - } - - utf8Chars.push_back(0x00); - utf8Chars.shrink_to_fit(); - - return utf8Chars; -} - -std::vector Encoding::utf8ToUtf16le(u8 *data, size_t length) { - std::vector utf16Chars; - utf16Chars.reserve(length / 2); - - for (u32 character = 0; character < length;) { - if ((data[character] & 0x80) == 0x00) { - utf16Chars.push_back(data[character]); - utf16Chars.push_back(0x00); - character++; - } - else if ((data[character] & 0xE0) == 0xC0) { - u16 decodedCharacter = (data[character + 1] & 0x3F) | ((data[character] & 0x1F) << 6); - utf16Chars.push_back(decodedCharacter & 0xFF); - utf16Chars.push_back(decodedCharacter >> 8); - character += 2; - } - else if ((data[character] & 0xF0) == 0xE0) { - u16 decodedCharacter = (data[character + 2] & 0x3F) | (data[character + 1] & 0x3F) << 6 | ((data[character] & 0x0F) << 12); - utf16Chars.push_back(decodedCharacter & 0xFF); - utf16Chars.push_back(decodedCharacter >> 8); - character += 3; - } - } - - utf16Chars.shrink_to_fit(); - - return utf16Chars; -} - -std::vector Encoding::utf8ToUtf16be(u8 *data, size_t length) { - std::vector utf16Chars; - utf16Chars.reserve(length / 2); - - for (u32 character = 0; character < length;) { - if ((data[character] & 0x80) == 0x00) { - utf16Chars.push_back(0x00); - utf16Chars.push_back(data[character]); - character++; - } - else if ((data[character] & 0xE0) == 0xC0) { - u16 decodedCharacter = (data[character + 1] & 0x3F) | ((data[character] & 0x1F) << 6); - utf16Chars.push_back(decodedCharacter >> 8); - utf16Chars.push_back(decodedCharacter & 0xFF); - character += 2; - } - else if ((data[character] & 0xF0) == 0xE0) { - u16 decodedCharacter = (data[character + 2] & 0x3F) | (data[character + 1] & 0x3F) << 6 | ((data[character] & 0x0F) << 12); - utf16Chars.push_back(decodedCharacter >> 8); - utf16Chars.push_back(decodedCharacter & 0xFF); - character += 3; - } - } - - utf16Chars.shrink_to_fit(); - - return utf16Chars; -} +#include "helpers/encoding.hpp" + +std::vector Encoding::uft16leToUtf8(u8 *data, size_t length) { + std::vector utf16Chars(length / 2); + std::vector utf8Chars; + utf8Chars.reserve(length / 2); + + for (u32 i = 0; i < length; i += 2) { + u16 c = data[i] | data[i + 1] << 8; + utf16Chars[i / 2] = c; + } + + for (u32 character = 0; character < length / 2; character++) { + u16 currChar = utf16Chars[character]; + + if (currChar <= 0x007F) { + utf8Chars.push_back(currChar & 0xFF); + } + else if (currChar <= 0x07FF) { + utf8Chars.push_back(0xC0 | ((currChar & 0x7C0) >> 6)); + utf8Chars.push_back(0x80 | (currChar & 0x3F)); + } + else { + utf8Chars.push_back(0xE0 | ((currChar & 0xF000) >> 12)); + utf8Chars.push_back(0x80 | ((currChar & 0xFC0) >> 6)); + utf8Chars.push_back(0x80 | (currChar & 0x3F)); + } + } + + utf8Chars.push_back(0x00); + utf8Chars.shrink_to_fit(); + + return utf8Chars; +} + +std::vector Encoding::uft16beToUtf8(u8 *data, size_t length) { + std::vector utf16Chars(length / 2); + std::vector utf8Chars; + utf8Chars.reserve(length / 2); + + for (u32 i = 0; i < length; i += 2) { + u16 c = data[i + 1] | data[i] << 8; + utf16Chars[i / 2] = c; + } + + for (u32 character = 0; character < length / 2; character++) { + u16 currChar = utf16Chars[character]; + + if (currChar <= 0x007F) { + utf8Chars.push_back(currChar & 0xFF); + } + else if (currChar <= 0x07FF) { + utf8Chars.push_back(0xC0 | ((currChar & 0x7C0) >> 6)); + utf8Chars.push_back(0x80 | (currChar & 0x3F)); + } + else { + utf8Chars.push_back(0xE0 | ((currChar & 0xF000) >> 12)); + utf8Chars.push_back(0x80 | ((currChar & 0xFC0) >> 6)); + utf8Chars.push_back(0x80 | (currChar & 0x3F)); + } + } + + utf8Chars.push_back(0x00); + utf8Chars.shrink_to_fit(); + + return utf8Chars; +} + +std::vector Encoding::utf8ToUtf16le(u8 *data, size_t length) { + std::vector utf16Chars; + utf16Chars.reserve(length / 2); + + for (u32 character = 0; character < length;) { + if ((data[character] & 0x80) == 0x00) { + utf16Chars.push_back(data[character]); + utf16Chars.push_back(0x00); + character++; + } + else if ((data[character] & 0xE0) == 0xC0) { + u16 decodedCharacter = (data[character + 1] & 0x3F) | ((data[character] & 0x1F) << 6); + utf16Chars.push_back(decodedCharacter & 0xFF); + utf16Chars.push_back(decodedCharacter >> 8); + character += 2; + } + else if ((data[character] & 0xF0) == 0xE0) { + u16 decodedCharacter = (data[character + 2] & 0x3F) | (data[character + 1] & 0x3F) << 6 | ((data[character] & 0x0F) << 12); + utf16Chars.push_back(decodedCharacter & 0xFF); + utf16Chars.push_back(decodedCharacter >> 8); + character += 3; + } + } + + utf16Chars.shrink_to_fit(); + + return utf16Chars; +} + +std::vector Encoding::utf8ToUtf16be(u8 *data, size_t length) { + std::vector utf16Chars; + utf16Chars.reserve(length / 2); + + for (u32 character = 0; character < length;) { + if ((data[character] & 0x80) == 0x00) { + utf16Chars.push_back(0x00); + utf16Chars.push_back(data[character]); + character++; + } + else if ((data[character] & 0xE0) == 0xC0) { + u16 decodedCharacter = (data[character + 1] & 0x3F) | ((data[character] & 0x1F) << 6); + utf16Chars.push_back(decodedCharacter >> 8); + utf16Chars.push_back(decodedCharacter & 0xFF); + character += 2; + } + else if ((data[character] & 0xF0) == 0xE0) { + u16 decodedCharacter = (data[character + 2] & 0x3F) | (data[character + 1] & 0x3F) << 6 | ((data[character] & 0x0F) << 12); + utf16Chars.push_back(decodedCharacter >> 8); + utf16Chars.push_back(decodedCharacter & 0xFF); + character += 3; + } + } + + utf16Chars.shrink_to_fit(); + + return utf16Chars; +} diff --git a/source/helpers/memory_dump.cpp b/source/helpers/memory_dump.cpp index 657ae01b..40b554a1 100644 --- a/source/helpers/memory_dump.cpp +++ b/source/helpers/memory_dump.cpp @@ -1,176 +1,176 @@ -#include "helpers/memory_dump.hpp" -#include - -#define BUFFER_SIZE 0x10000 - -MemoryDump::MemoryDump(std::string filePath, DumpType dumpType, bool discardFile) : m_filePath(filePath) { - m_dataHeader = { 0 }; - - m_dataHeader.magic = 0x4E5A4445; - m_dataHeader.endOfHeader = '@'; - m_dataHeader.dumpType = (char)dumpType; - - m_dataHeader.searchDataType = SEARCH_TYPE_NONE; - m_dataHeader.searchMode = SEARCH_MODE_NONE; - m_dataHeader.searchRegion = SEARCH_REGION_NONE; - - m_dumpFile = fopen(filePath.c_str(), "r"); - - if (m_dumpFile == nullptr) { - m_dumpFile = fopen(filePath.c_str(), "w+b"); - - MemoryDump::writeHeader(); - } else { - fclose(m_dumpFile); - - if (discardFile) { - m_dumpFile = fopen(filePath.c_str(), "w+b"); - MemoryDump::writeHeader(); - } else { - m_dumpFile = fopen(filePath.c_str(), "r+b"); - fseek(m_dumpFile, 0, SEEK_END); - - size_t fileSize = ftell(m_dumpFile); - - if (fileSize >= sizeof(DataHeader)) { - fseek(m_dumpFile, 0, SEEK_SET); - fread(&m_dataHeader, sizeof(m_dataHeader), 1, m_dumpFile); - } - } - - } - - m_data.reserve(BUFFER_SIZE); -} - -MemoryDump::~MemoryDump() { - if (isFileOpen()) { - MemoryDump::flushBuffer(); - fclose(m_dumpFile); - } -} - -void MemoryDump::setBaseAddresses(u64 addrSpaceBase, u64 heapBase, u64 mainBase, u64 heapSize, u64 mainSize) { - m_dataHeader.addrSpaceBaseAddress = addrSpaceBase; - m_dataHeader.heapBaseAddress = heapBase; - m_dataHeader.mainBaseAddress = mainBase; - - m_dataHeader.heapSize = heapSize; - m_dataHeader.mainSize = mainSize; - - MemoryDump::writeHeader(); -} - -void MemoryDump::setSearchParams(searchType_t searchDataType, searchMode_t searchMode, searchRegion_t searchRegion, searchValue_t searchValue1, searchValue_t searchValue2) { - m_dataHeader.searchDataType = searchDataType; - m_dataHeader.searchMode = searchMode; - m_dataHeader.searchRegion = searchRegion; - m_dataHeader.searchValue[0] = searchValue1; - m_dataHeader.searchValue[1] = searchValue2; - - MemoryDump::writeHeader(); -} - -void MemoryDump::addData(u8 *buffer, size_t dataSize) { - if ((m_data.size() + dataSize) < BUFFER_SIZE) { - std::copy(buffer, buffer + dataSize, std::back_inserter(m_data)); - } else if (dataSize <= BUFFER_SIZE) { - if (isFileOpen()) { - MemoryDump::flushBuffer(); - std::copy(buffer, buffer + dataSize, std::back_inserter(m_data)); - } - } else { - if (isFileOpen()) { - fseek(m_dumpFile, 0, SEEK_END); - - MemoryDump::flushBuffer(); - - fwrite(buffer, sizeof(u8), dataSize, m_dumpFile); - m_dataHeader.dataSize += dataSize; - MemoryDump::writeHeader(); - } - } -} - -size_t MemoryDump::size() { - MemoryDump::flushBuffer(); - - return m_dataHeader.dataSize; -} - -void MemoryDump::clear() { - m_data.clear(); - m_dataHeader.dataSize = 0; - m_dataHeader.dumpType = DumpType::UNDEFINED; - - if (isFileOpen()) { - fclose(m_dumpFile); - m_dumpFile = nullptr; - } - - m_dumpFile = fopen(m_filePath.c_str(), "w+b"); - MemoryDump::writeHeader(); -} - -int MemoryDump::getData(u64 addr, void *buffer, size_t bufferSize) { - if (!isFileOpen()) return 1; - - MemoryDump::flushBuffer(); - - fseek(m_dumpFile, sizeof(struct DataHeader) + addr, SEEK_SET); - fread(buffer, sizeof(u8), bufferSize, m_dumpFile); - - return 0; -} - -u8 MemoryDump::operator[](u64 index) { - u8 data = 0; - - if (!isFileOpen()) return 0; - - MemoryDump::flushBuffer(); - - fseek(m_dumpFile, sizeof(struct DataHeader) + index, SEEK_SET); - fread(&data, sizeof(u8), 1, m_dumpFile); - - return data; -} - -bool MemoryDump::isFileOpen() { - return m_dumpFile != nullptr; -} - -void MemoryDump::flushBuffer() { - if (m_data.size() > 0 && isFileOpen()) { - fseek(m_dumpFile, 0, SEEK_END); - fwrite(&m_data[0], sizeof(u8), m_data.size(), m_dumpFile); - - m_dataHeader.dataSize += m_data.size(); - - m_data.clear(); - - MemoryDump::writeHeader(); - } -} - -void MemoryDump::writeHeader() { - if (isFileOpen()) { - fseek(m_dumpFile, 0, SEEK_SET); - fwrite(&m_dataHeader, sizeof(m_dataHeader), 1, m_dumpFile); - fflush(m_dumpFile); - } -} - -data_header_t MemoryDump::getDumpInfo() { - return m_dataHeader; -} - -void MemoryDump::setDumpType(DumpType dumpType) { - if (m_dataHeader.dumpType != UNDEFINED) { - m_dataHeader.dumpType = dumpType; - MemoryDump::clear(); - } else { - m_dataHeader.dumpType = dumpType; - MemoryDump::writeHeader(); - } +#include "helpers/memory_dump.hpp" +#include + +#define BUFFER_SIZE 0x10000 + +MemoryDump::MemoryDump(std::string filePath, DumpType dumpType, bool discardFile) : m_filePath(filePath) { + m_dataHeader = { 0 }; + + m_dataHeader.magic = 0x4E5A4445; + m_dataHeader.endOfHeader = '@'; + m_dataHeader.dumpType = (char)dumpType; + + m_dataHeader.searchDataType = SEARCH_TYPE_NONE; + m_dataHeader.searchMode = SEARCH_MODE_NONE; + m_dataHeader.searchRegion = SEARCH_REGION_NONE; + + m_dumpFile = fopen(filePath.c_str(), "r"); + + if (m_dumpFile == nullptr) { + m_dumpFile = fopen(filePath.c_str(), "w+b"); + + MemoryDump::writeHeader(); + } else { + fclose(m_dumpFile); + + if (discardFile) { + m_dumpFile = fopen(filePath.c_str(), "w+b"); + MemoryDump::writeHeader(); + } else { + m_dumpFile = fopen(filePath.c_str(), "r+b"); + fseek(m_dumpFile, 0, SEEK_END); + + size_t fileSize = ftell(m_dumpFile); + + if (fileSize >= sizeof(DataHeader)) { + fseek(m_dumpFile, 0, SEEK_SET); + fread(&m_dataHeader, sizeof(m_dataHeader), 1, m_dumpFile); + } + } + + } + + m_data.reserve(BUFFER_SIZE); +} + +MemoryDump::~MemoryDump() { + if (isFileOpen()) { + MemoryDump::flushBuffer(); + fclose(m_dumpFile); + } +} + +void MemoryDump::setBaseAddresses(u64 addrSpaceBase, u64 heapBase, u64 mainBase, u64 heapSize, u64 mainSize) { + m_dataHeader.addrSpaceBaseAddress = addrSpaceBase; + m_dataHeader.heapBaseAddress = heapBase; + m_dataHeader.mainBaseAddress = mainBase; + + m_dataHeader.heapSize = heapSize; + m_dataHeader.mainSize = mainSize; + + MemoryDump::writeHeader(); +} + +void MemoryDump::setSearchParams(searchType_t searchDataType, searchMode_t searchMode, searchRegion_t searchRegion, searchValue_t searchValue1, searchValue_t searchValue2) { + m_dataHeader.searchDataType = searchDataType; + m_dataHeader.searchMode = searchMode; + m_dataHeader.searchRegion = searchRegion; + m_dataHeader.searchValue[0] = searchValue1; + m_dataHeader.searchValue[1] = searchValue2; + + MemoryDump::writeHeader(); +} + +void MemoryDump::addData(u8 *buffer, size_t dataSize) { + if ((m_data.size() + dataSize) < BUFFER_SIZE) { + std::copy(buffer, buffer + dataSize, std::back_inserter(m_data)); + } else if (dataSize <= BUFFER_SIZE) { + if (isFileOpen()) { + MemoryDump::flushBuffer(); + std::copy(buffer, buffer + dataSize, std::back_inserter(m_data)); + } + } else { + if (isFileOpen()) { + fseek(m_dumpFile, 0, SEEK_END); + + MemoryDump::flushBuffer(); + + fwrite(buffer, sizeof(u8), dataSize, m_dumpFile); + m_dataHeader.dataSize += dataSize; + MemoryDump::writeHeader(); + } + } +} + +size_t MemoryDump::size() { + MemoryDump::flushBuffer(); + + return m_dataHeader.dataSize; +} + +void MemoryDump::clear() { + m_data.clear(); + m_dataHeader.dataSize = 0; + m_dataHeader.dumpType = DumpType::UNDEFINED; + + if (isFileOpen()) { + fclose(m_dumpFile); + m_dumpFile = nullptr; + } + + m_dumpFile = fopen(m_filePath.c_str(), "w+b"); + MemoryDump::writeHeader(); +} + +int MemoryDump::getData(u64 addr, void *buffer, size_t bufferSize) { + if (!isFileOpen()) return 1; + + MemoryDump::flushBuffer(); + + fseek(m_dumpFile, sizeof(struct DataHeader) + addr, SEEK_SET); + fread(buffer, sizeof(u8), bufferSize, m_dumpFile); + + return 0; +} + +u8 MemoryDump::operator[](u64 index) { + u8 data = 0; + + if (!isFileOpen()) return 0; + + MemoryDump::flushBuffer(); + + fseek(m_dumpFile, sizeof(struct DataHeader) + index, SEEK_SET); + fread(&data, sizeof(u8), 1, m_dumpFile); + + return data; +} + +bool MemoryDump::isFileOpen() { + return m_dumpFile != nullptr; +} + +void MemoryDump::flushBuffer() { + if (m_data.size() > 0 && isFileOpen()) { + fseek(m_dumpFile, 0, SEEK_END); + fwrite(&m_data[0], sizeof(u8), m_data.size(), m_dumpFile); + + m_dataHeader.dataSize += m_data.size(); + + m_data.clear(); + + MemoryDump::writeHeader(); + } +} + +void MemoryDump::writeHeader() { + if (isFileOpen()) { + fseek(m_dumpFile, 0, SEEK_SET); + fwrite(&m_dataHeader, sizeof(m_dataHeader), 1, m_dumpFile); + fflush(m_dumpFile); + } +} + +data_header_t MemoryDump::getDumpInfo() { + return m_dataHeader; +} + +void MemoryDump::setDumpType(DumpType dumpType) { + if (m_dataHeader.dumpType != UNDEFINED) { + m_dataHeader.dumpType = dumpType; + MemoryDump::clear(); + } else { + m_dataHeader.dumpType = dumpType; + MemoryDump::writeHeader(); + } } \ No newline at end of file diff --git a/source/helpers/save.cpp b/source/helpers/save.cpp index 7eac90df..385dd622 100644 --- a/source/helpers/save.cpp +++ b/source/helpers/save.cpp @@ -1,451 +1,451 @@ -#include "helpers/save.hpp" - -#include -#include -#include - -#include "helpers/account.hpp" -#include "helpers/title.hpp" - -using json = nlohmann::json; - -s32 deleteDirRecursively(const char *path, bool isSave) { - DIR *d = opendir(path); - size_t path_len = strlen(path); - s32 r = -1; - - if (d) { - struct dirent *p; - - r = 0; - - while (!r && (p=readdir(d))) { - s32 r2 = -1; - char *buf; - size_t len; - - /* Skip the names "." and ".." as we don't want to recurse on them. */ - if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { - continue; - } - - len = path_len + strlen(p->d_name) + 2; - buf = new char[len]; - - if (buf) { - struct stat statbuf; - - snprintf(buf, len, "%s/%s", path, p->d_name); - - if (!stat(buf, &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) - r2 = deleteDirRecursively(buf, isSave); - else - r2 = unlink(buf); - } - - delete[] buf; - } - - r = r2; - } - - closedir(d); - } - - if (!r) - r = rmdir(path); - - - if (isSave && R_FAILED(fsdevCommitDevice(SAVE_DEV))) { - printf("Committing failed.\n"); - return -3; - } - - return r; -} - -bool doesFolderExist(const char *path) { - struct stat sb; - - return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode); -} - -bool makeExInjDir(char ptr[0x100], u64 titleID, u128 userID, bool isInject, const char* injectFolder, bool fromBatch, std::string backupName) { - std::stringstream ss; - std::string folder_path(EDIZON_DIR); - - json metadata; - std::string metadata_string; - std::ofstream metadata_file; - std::stringstream metadata_user_id; - std::stringstream metadata_title_id; - - if (!fromBatch) { - folder_path += "/saves/"; - mkdir(folder_path.c_str(), 0700); - ss << folder_path << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) - << std::hex << titleID << "/"; - mkdir(ss.str().c_str(), 0700); - - std::string titleName = ss.str(); - titleName += Title::g_titles[titleID]->getTitleName(); - fclose(fopen(titleName.c_str(), "ab+")); - - if (isInject) - ss << injectFolder << "/"; - else - ss << backupName << "/"; - } - else { - folder_path += "/batch_saves/"; - mkdir(folder_path.c_str(), 0700); - ss << folder_path << backupName << "/"; - - - mkdir(ss.str().c_str(), 0700); - - u64 userIDH = userID >> 64; - u64 userIDL = userID & 0xFFFFFFFFFFFFFFFFULL; - - ss << std::setfill('0') << std::uppercase << std::hex << userIDH << std::setfill('0') << std::uppercase << std::hex << userIDL << "/"; - mkdir(ss.str().c_str(), 0700); - - ss << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) - << std::hex << titleID << "/"; - } - - if(doesFolderExist(ss.str().c_str())) return false; - strcpy(ptr, ss.str().c_str()); - mkdir(ptr, 0700); - - metadata.clear(); - - u64 userIDH = userID >> 64; - u64 userIDL = userID & 0xFFFFFFFFFFFFFFFFULL; - metadata_user_id << std::setfill('0') << std::uppercase << std::hex << userIDH; - metadata_user_id << std::setfill('0') << std::uppercase << std::hex << userIDL; - metadata["user_id"] = metadata_user_id.str(); - - metadata["user_name"] = Account::g_accounts[userID]->getUserName(); - - metadata_title_id << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) << std::hex << titleID; - metadata["title_id"] = metadata_title_id.str(); - - metadata["title_name"] = Title::g_titles[titleID]->getTitleName(); - metadata["title_version"] = Title::g_titles[titleID]->getTitleVersion(); - metadata_string = metadata.dump(4); - - - metadata_file.open (ss.str() + "edizon_save_metadata.json"); - metadata_file << metadata_string << "\n"; - metadata_file.close(); - - return true; -} - -Result _getSaveList(std::vector & saveInfoList) { - Result rc=0; - FsSaveDataIterator iterator; - size_t total_entries=0; - FsSaveDataInfo info; - - rc = fsOpenSaveDataIterator(&iterator, FsSaveDataSpaceId_NandUser);//See libnx fs.h. - if (R_FAILED(rc)) { - printf("fsOpenSaveDataIterator() failed: 0x%x\n", rc); - return rc; - } - - rc = fsSaveDataIteratorRead(&iterator, &info, 1, &total_entries);//See libnx fs.h. - if (R_FAILED(rc)) - return rc; - if (total_entries == 0) - return MAKERESULT(Module_Libnx, LibnxError_NotFound); - - for (; R_SUCCEEDED(rc) && total_entries > 0; - rc = fsSaveDataIteratorRead(&iterator, &info, 1, &total_entries)) { - if (info.saveDataType == FsSaveDataType_SaveData) { - saveInfoList.push_back(info); - } - } - - fsSaveDataIteratorClose(&iterator); - - return 0; -} - -Result mountSaveByTitleAccountIDs(const u64 titleID, const u128 userID, FsFileSystem& tmpfs) { - Result rc = 0; - - rc = fsMount_SaveData(&tmpfs, titleID, userID);//See also libnx fs.h. - if (R_FAILED(rc)) { - printf("fsMount_SaveData() failed: 0x%x\n", rc); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&tmpfs); - return rc; - } - - s32 ret = fsdevMountDevice(SAVE_DEV, tmpfs); - if (ret == -1) { - printf("fsdevMountDevice() failed.\n"); - rc = ret; - } - return rc; -} - -s32 isDirectory(const char *path) { - struct stat statbuf; - - if (stat(path, &statbuf) != 0) - return 0; - - return S_ISDIR(statbuf.st_mode); -} - -s32 cpFile(std::string srcPath, std::string dstPath) { - FILE* src = fopen(srcPath.c_str(), "rb"); - FILE* dst = fopen(dstPath.c_str(), "wb+"); - - if (src == nullptr || dst == nullptr) - return - 1; - - fseek(src, 0, SEEK_END); - rewind(src); - - size_t size; - char* buf = new char[0x50000]; - - u64 offset = 0; - size_t slashpos = srcPath.rfind("/"); - std::string name = srcPath.substr(slashpos + 1, srcPath.length() - slashpos - 1); - while ((size = fread(buf, 1, 0x50000, src)) > 0) { - fwrite(buf, 1, size, dst); - offset += size; - } - - delete[] buf; - fclose(src); - fclose(dst); - - return 0; -} - -s32 copyAllSave(const char * path, bool isInject, const char exInjDir[0x100]) { - DIR* dir; - struct dirent* ent; - - char filenameSave[0x100]; - char filenameSD[0x100]; - - strcpy(filenameSave, "save:/"); - strcat(filenameSave, path); - - strcpy(filenameSD, exInjDir); - strcat(filenameSD, path); - - if (isInject) - dir = opendir(filenameSD); - else - dir = opendir(filenameSave); - - if (dir == nullptr) { - printf("Failed to open dir: %s\n", isInject ? filenameSD : filenameSave); - return -1; - } - else { - while ((ent = readdir(dir))) { - if (strcmp(ent->d_name, "edizon_save_metadata.json") == 0) continue; - - char filename[0x100]; - - strcpy(filename, path); - strcat(filename, "/"); - strcat(filename, ent->d_name); - - strcpy(filenameSave, "save:/"); - strcat(filenameSave, filename); - - strcpy(filenameSD, exInjDir); - strcat(filenameSD, filename); - - if (isDirectory(isInject ? filenameSD : filenameSave)) { - if (isInject) { - mkdir(filenameSave, 0700); - if (R_FAILED(fsdevCommitDevice(SAVE_DEV))) - printf("Failed to commit directory %s.", filenameSave); - } else - mkdir(filenameSD, 0700); - s32 res = copyAllSave(filename, isInject, exInjDir); - if (res != 0) - return res; - } else { - printf("Copying %s... ", filename); - - if (isInject) { - cpFile(std::string(filenameSD), std::string(filenameSave)); - - if (R_SUCCEEDED(fsdevCommitDevice(SAVE_DEV))) { // Thx yellows8 - printf("committed.\n"); - } else { - printf("fsdevCommitDevice() failed...\n"); - return -2; - } - } else { - cpFile(std::string(filenameSave), std::string(filenameSD)); - printf("\n"); - } - } - } - closedir(dir); - return 0; - } -} - -s32 backupSave(u64 titleID, u128 userID, bool fromBatch, std::string backupName) { - FsFileSystem fs; - s32 res = 0; - - if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { - printf("Failed to mount save.\n"); - return 1; - } - - char *ptr = new char[0x100]; - - if(!makeExInjDir(ptr, titleID, userID, false, nullptr, fromBatch, backupName)) { - fsdevUnmountDevice(SAVE_DEV); - delete[] ptr; - return 2; - } - - if (ptr == nullptr) { - printf("makeExInjDir failed.\n"); - fsdevUnmountDevice(SAVE_DEV); - delete[] ptr; - return 3; - } - - res = copyAllSave("", false, ptr); - fsdevUnmountDevice(SAVE_DEV); - - delete[] ptr; - - return res; -} - -s32 restoreSave(u64 titleID, u128 userID, const char* path) { - FsFileSystem fs; - s32 res = 0; - - if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { - printf("Failed to mount save.\n"); - return 1; - } - - if (path == nullptr) { - printf("makeExInjDir failed.\n"); - fsdevUnmountDevice(SAVE_DEV); - return 2; - } - - res = deleteDirRecursively("save:/", true); - - if (!res) { - printf("Deleting save:/ failed: %d.\n", res); - return 3; - } - - res = copyAllSave("", true, path); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - - return res; -} - -s32 loadSaveFile(std::vector *buffer, size_t *length, u64 titleID, u128 userID, const char *path) { - FsFileSystem fs; - size_t size; - - if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { - printf("Failed to mount save.\n"); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - return -1; - } - - char filePath[0x100]; - - strcpy(filePath, "save:/"); - strcat(filePath, path); - - - FILE *file = fopen(filePath, "rb"); - - if (file == nullptr) { - printf("Failed to open file.\n"); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - return -2; - } - - fseek(file, 0, SEEK_END); - size = ftell(file); - rewind(file); - - if (size <= 0) { - printf("File reading failed. File length is %zu.\n", size); - fclose(file); - fsdevUnmountDevice(SAVE_DEV); - return -3; - } - - buffer->reserve(size); - fread(&(*buffer)[0], size, 1, file); - fclose(file); - - *length = size; - - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - - return 0; -} - -s32 storeSaveFile(u8 *buffer, size_t length, u64 titleID, u128 userID, const char *path) { - FsFileSystem fs; - - if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { - printf("Failed to mount save.\n"); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - return -1; - } - - char filePath[0x100]; - - strcpy(filePath, "save:/"); - strcat(filePath, path); - - - FILE *file = fopen(filePath, "wb"); - - if (file == nullptr) { - printf("Failed to open file.\n"); - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - return -2; - } - - fwrite(buffer, length, 1, file); - fclose(file); - - if (R_FAILED(fsdevCommitDevice(SAVE_DEV))) { - printf("Committing failed.\n"); - return -3; - } - - fsdevUnmountDevice(SAVE_DEV); - fsFsClose(&fs); - - return 0; -} +#include "helpers/save.hpp" + +#include +#include +#include + +#include "helpers/account.hpp" +#include "helpers/title.hpp" + +using json = nlohmann::json; + +s32 deleteDirRecursively(const char *path, bool isSave) { + DIR *d = opendir(path); + size_t path_len = strlen(path); + s32 r = -1; + + if (d) { + struct dirent *p; + + r = 0; + + while (!r && (p=readdir(d))) { + s32 r2 = -1; + char *buf; + size_t len; + + /* Skip the names "." and ".." as we don't want to recurse on them. */ + if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { + continue; + } + + len = path_len + strlen(p->d_name) + 2; + buf = new char[len]; + + if (buf) { + struct stat statbuf; + + snprintf(buf, len, "%s/%s", path, p->d_name); + + if (!stat(buf, &statbuf)) { + if (S_ISDIR(statbuf.st_mode)) + r2 = deleteDirRecursively(buf, isSave); + else + r2 = unlink(buf); + } + + delete[] buf; + } + + r = r2; + } + + closedir(d); + } + + if (!r) + r = rmdir(path); + + + if (isSave && R_FAILED(fsdevCommitDevice(SAVE_DEV))) { + printf("Committing failed.\n"); + return -3; + } + + return r; +} + +bool doesFolderExist(const char *path) { + struct stat sb; + + return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode); +} + +bool makeExInjDir(char ptr[0x100], u64 titleID, u128 userID, bool isInject, const char* injectFolder, bool fromBatch, std::string backupName) { + std::stringstream ss; + std::string folder_path(EDIZON_DIR); + + json metadata; + std::string metadata_string; + std::ofstream metadata_file; + std::stringstream metadata_user_id; + std::stringstream metadata_title_id; + + if (!fromBatch) { + folder_path += "/saves/"; + mkdir(folder_path.c_str(), 0700); + ss << folder_path << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) + << std::hex << titleID << "/"; + mkdir(ss.str().c_str(), 0700); + + std::string titleName = ss.str(); + titleName += Title::g_titles[titleID]->getTitleName(); + fclose(fopen(titleName.c_str(), "ab+")); + + if (isInject) + ss << injectFolder << "/"; + else + ss << backupName << "/"; + } + else { + folder_path += "/batch_saves/"; + mkdir(folder_path.c_str(), 0700); + ss << folder_path << backupName << "/"; + + + mkdir(ss.str().c_str(), 0700); + + u64 userIDH = userID >> 64; + u64 userIDL = userID & 0xFFFFFFFFFFFFFFFFULL; + + ss << std::setfill('0') << std::uppercase << std::hex << userIDH << std::setfill('0') << std::uppercase << std::hex << userIDL << "/"; + mkdir(ss.str().c_str(), 0700); + + ss << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) + << std::hex << titleID << "/"; + } + + if(doesFolderExist(ss.str().c_str())) return false; + strcpy(ptr, ss.str().c_str()); + mkdir(ptr, 0700); + + metadata.clear(); + + u64 userIDH = userID >> 64; + u64 userIDL = userID & 0xFFFFFFFFFFFFFFFFULL; + metadata_user_id << std::setfill('0') << std::uppercase << std::hex << userIDH; + metadata_user_id << std::setfill('0') << std::uppercase << std::hex << userIDL; + metadata["user_id"] = metadata_user_id.str(); + + metadata["user_name"] = Account::g_accounts[userID]->getUserName(); + + metadata_title_id << std::uppercase << std::setfill('0') << std::setw(sizeof(titleID)*2) << std::hex << titleID; + metadata["title_id"] = metadata_title_id.str(); + + metadata["title_name"] = Title::g_titles[titleID]->getTitleName(); + metadata["title_version"] = Title::g_titles[titleID]->getTitleVersion(); + metadata_string = metadata.dump(4); + + + metadata_file.open (ss.str() + "edizon_save_metadata.json"); + metadata_file << metadata_string << "\n"; + metadata_file.close(); + + return true; +} + +Result _getSaveList(std::vector & saveInfoList) { + Result rc=0; + FsSaveDataIterator iterator; + size_t total_entries=0; + FsSaveDataInfo info; + + rc = fsOpenSaveDataIterator(&iterator, FsSaveDataSpaceId_NandUser);//See libnx fs.h. + if (R_FAILED(rc)) { + printf("fsOpenSaveDataIterator() failed: 0x%x\n", rc); + return rc; + } + + rc = fsSaveDataIteratorRead(&iterator, &info, 1, &total_entries);//See libnx fs.h. + if (R_FAILED(rc)) + return rc; + if (total_entries == 0) + return MAKERESULT(Module_Libnx, LibnxError_NotFound); + + for (; R_SUCCEEDED(rc) && total_entries > 0; + rc = fsSaveDataIteratorRead(&iterator, &info, 1, &total_entries)) { + if (info.saveDataType == FsSaveDataType_SaveData) { + saveInfoList.push_back(info); + } + } + + fsSaveDataIteratorClose(&iterator); + + return 0; +} + +Result mountSaveByTitleAccountIDs(const u64 titleID, const u128 userID, FsFileSystem& tmpfs) { + Result rc = 0; + + rc = fsMount_SaveData(&tmpfs, titleID, userID);//See also libnx fs.h. + if (R_FAILED(rc)) { + printf("fsMount_SaveData() failed: 0x%x\n", rc); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&tmpfs); + return rc; + } + + s32 ret = fsdevMountDevice(SAVE_DEV, tmpfs); + if (ret == -1) { + printf("fsdevMountDevice() failed.\n"); + rc = ret; + } + return rc; +} + +s32 isDirectory(const char *path) { + struct stat statbuf; + + if (stat(path, &statbuf) != 0) + return 0; + + return S_ISDIR(statbuf.st_mode); +} + +s32 cpFile(std::string srcPath, std::string dstPath) { + FILE* src = fopen(srcPath.c_str(), "rb"); + FILE* dst = fopen(dstPath.c_str(), "wb+"); + + if (src == nullptr || dst == nullptr) + return - 1; + + fseek(src, 0, SEEK_END); + rewind(src); + + size_t size; + char* buf = new char[0x50000]; + + u64 offset = 0; + size_t slashpos = srcPath.rfind("/"); + std::string name = srcPath.substr(slashpos + 1, srcPath.length() - slashpos - 1); + while ((size = fread(buf, 1, 0x50000, src)) > 0) { + fwrite(buf, 1, size, dst); + offset += size; + } + + delete[] buf; + fclose(src); + fclose(dst); + + return 0; +} + +s32 copyAllSave(const char * path, bool isInject, const char exInjDir[0x100]) { + DIR* dir; + struct dirent* ent; + + char filenameSave[0x100]; + char filenameSD[0x100]; + + strcpy(filenameSave, "save:/"); + strcat(filenameSave, path); + + strcpy(filenameSD, exInjDir); + strcat(filenameSD, path); + + if (isInject) + dir = opendir(filenameSD); + else + dir = opendir(filenameSave); + + if (dir == nullptr) { + printf("Failed to open dir: %s\n", isInject ? filenameSD : filenameSave); + return -1; + } + else { + while ((ent = readdir(dir))) { + if (strcmp(ent->d_name, "edizon_save_metadata.json") == 0) continue; + + char filename[0x100]; + + strcpy(filename, path); + strcat(filename, "/"); + strcat(filename, ent->d_name); + + strcpy(filenameSave, "save:/"); + strcat(filenameSave, filename); + + strcpy(filenameSD, exInjDir); + strcat(filenameSD, filename); + + if (isDirectory(isInject ? filenameSD : filenameSave)) { + if (isInject) { + mkdir(filenameSave, 0700); + if (R_FAILED(fsdevCommitDevice(SAVE_DEV))) + printf("Failed to commit directory %s.", filenameSave); + } else + mkdir(filenameSD, 0700); + s32 res = copyAllSave(filename, isInject, exInjDir); + if (res != 0) + return res; + } else { + printf("Copying %s... ", filename); + + if (isInject) { + cpFile(std::string(filenameSD), std::string(filenameSave)); + + if (R_SUCCEEDED(fsdevCommitDevice(SAVE_DEV))) { // Thx yellows8 + printf("committed.\n"); + } else { + printf("fsdevCommitDevice() failed...\n"); + return -2; + } + } else { + cpFile(std::string(filenameSave), std::string(filenameSD)); + printf("\n"); + } + } + } + closedir(dir); + return 0; + } +} + +s32 backupSave(u64 titleID, u128 userID, bool fromBatch, std::string backupName) { + FsFileSystem fs; + s32 res = 0; + + if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { + printf("Failed to mount save.\n"); + return 1; + } + + char *ptr = new char[0x100]; + + if(!makeExInjDir(ptr, titleID, userID, false, nullptr, fromBatch, backupName)) { + fsdevUnmountDevice(SAVE_DEV); + delete[] ptr; + return 2; + } + + if (ptr == nullptr) { + printf("makeExInjDir failed.\n"); + fsdevUnmountDevice(SAVE_DEV); + delete[] ptr; + return 3; + } + + res = copyAllSave("", false, ptr); + fsdevUnmountDevice(SAVE_DEV); + + delete[] ptr; + + return res; +} + +s32 restoreSave(u64 titleID, u128 userID, const char* path) { + FsFileSystem fs; + s32 res = 0; + + if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { + printf("Failed to mount save.\n"); + return 1; + } + + if (path == nullptr) { + printf("makeExInjDir failed.\n"); + fsdevUnmountDevice(SAVE_DEV); + return 2; + } + + res = deleteDirRecursively("save:/", true); + + if (!res) { + printf("Deleting save:/ failed: %d.\n", res); + return 3; + } + + res = copyAllSave("", true, path); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + + return res; +} + +s32 loadSaveFile(std::vector *buffer, size_t *length, u64 titleID, u128 userID, const char *path) { + FsFileSystem fs; + size_t size; + + if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { + printf("Failed to mount save.\n"); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + return -1; + } + + char filePath[0x100]; + + strcpy(filePath, "save:/"); + strcat(filePath, path); + + + FILE *file = fopen(filePath, "rb"); + + if (file == nullptr) { + printf("Failed to open file.\n"); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + return -2; + } + + fseek(file, 0, SEEK_END); + size = ftell(file); + rewind(file); + + if (size <= 0) { + printf("File reading failed. File length is %zu.\n", size); + fclose(file); + fsdevUnmountDevice(SAVE_DEV); + return -3; + } + + buffer->reserve(size); + fread(&(*buffer)[0], size, 1, file); + fclose(file); + + *length = size; + + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + + return 0; +} + +s32 storeSaveFile(u8 *buffer, size_t length, u64 titleID, u128 userID, const char *path) { + FsFileSystem fs; + + if (R_FAILED(mountSaveByTitleAccountIDs(titleID, userID, fs))) { + printf("Failed to mount save.\n"); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + return -1; + } + + char filePath[0x100]; + + strcpy(filePath, "save:/"); + strcat(filePath, path); + + + FILE *file = fopen(filePath, "wb"); + + if (file == nullptr) { + printf("Failed to open file.\n"); + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + return -2; + } + + fwrite(buffer, length, 1, file); + fclose(file); + + if (R_FAILED(fsdevCommitDevice(SAVE_DEV))) { + printf("Committing failed.\n"); + return -3; + } + + fsdevUnmountDevice(SAVE_DEV); + fsFsClose(&fs); + + return 0; +} diff --git a/source/helpers/title.cpp b/source/helpers/title.cpp index 1f614537..31191bba 100644 --- a/source/helpers/title.cpp +++ b/source/helpers/title.cpp @@ -1,105 +1,105 @@ -#include "helpers/title.hpp" - -extern "C" { - #include "nanojpeg.h" -} - -Title::Title(FsSaveDataInfo& saveInfo) { - Result rc=0; - - std::unique_ptr buf = std::make_unique(); - size_t outsize=0; - - NacpLanguageEntry *langentry = nullptr; - - if (buf == nullptr) { - m_errorCode = 1; - return; - } - memset(buf.get(), 0, sizeof(NsApplicationControlData)); - - rc = nsGetApplicationControlData(1, saveInfo.titleID, buf.get(), sizeof(NsApplicationControlData), &outsize); - if (R_FAILED(rc)) { - m_errorCode = 2; - return; - } - - if (outsize < sizeof(buf->nacp)) { - m_errorCode = 3; - return; - } - - rc = nacpGetLanguageEntry(&buf->nacp, &langentry); - if (R_FAILED(rc) || langentry==nullptr) { - m_errorCode = 4; - return; - } - - m_titleName = std::string(langentry->name); - m_titleAuthor = std::string(langentry->author); - m_titleVersion = std::string(buf->nacp.version); - - m_titleID = saveInfo.titleID; - - njInit(); - - size_t iconbytesize = outsize-sizeof(buf->nacp); - size_t imagesize = 256 * 256 * 3; - - if (njDecode(buf->icon, iconbytesize) != NJ_OK) { - m_errorCode = 5; - njDone(); - return; - } - - if (njGetWidth() != 256 || njGetHeight() != 256 || (size_t)njGetImageSize() != imagesize || njIsColor() != 1) { - m_errorCode = 6; - njDone(); - return; - } - - u8* ptr = nullptr; - - ptr = njGetImage(); - if (ptr == nullptr) { - m_errorCode = 7; - njDone(); - return; - } - - memcpy(m_titleIcon, ptr, imagesize); - ptr = nullptr; - - njDone(); -} - -Title::~Title() { -} - -std::string Title::getTitleName() { - return m_titleName; -} - -std::string Title::getTitleAuthor() { - return m_titleAuthor; -} - -std::string Title::getTitleVersion() { - return m_titleVersion; -} - -u8* Title::getTitleIcon() { - return m_titleIcon; -} - -u64 Title::getTitleID() { - return m_titleID; -} - -std::vector Title::getUserIDs() { - return m_userIDs; -} - -void Title::addUserID(u128 userID) { - m_userIDs.push_back(userID); -} +#include "helpers/title.hpp" + +extern "C" { + #include "nanojpeg.h" +} + +Title::Title(FsSaveDataInfo& saveInfo) { + Result rc=0; + + std::unique_ptr buf = std::make_unique(); + size_t outsize=0; + + NacpLanguageEntry *langentry = nullptr; + + if (buf == nullptr) { + m_errorCode = 1; + return; + } + memset(buf.get(), 0, sizeof(NsApplicationControlData)); + + rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, saveInfo.titleID, buf.get(), sizeof(NsApplicationControlData), &outsize); + if (R_FAILED(rc)) { + m_errorCode = 2; + return; + } + + if (outsize < sizeof(buf->nacp)) { + m_errorCode = 3; + return; + } + + rc = nacpGetLanguageEntry(&buf->nacp, &langentry); + if (R_FAILED(rc) || langentry==nullptr) { + m_errorCode = 4; + return; + } + + m_titleName = std::string(langentry->name); + m_titleAuthor = std::string(langentry->author); + m_titleVersion = std::string(buf->nacp.version); + + m_titleID = saveInfo.titleID; + + njInit(); + + size_t iconbytesize = outsize-sizeof(buf->nacp); + size_t imagesize = 256 * 256 * 3; + + if (njDecode(buf->icon, iconbytesize) != NJ_OK) { + m_errorCode = 5; + njDone(); + return; + } + + if (njGetWidth() != 256 || njGetHeight() != 256 || (size_t)njGetImageSize() != imagesize || njIsColor() != 1) { + m_errorCode = 6; + njDone(); + return; + } + + u8* ptr = nullptr; + + ptr = njGetImage(); + if (ptr == nullptr) { + m_errorCode = 7; + njDone(); + return; + } + + memcpy(m_titleIcon, ptr, imagesize); + ptr = nullptr; + + njDone(); +} + +Title::~Title() { +} + +std::string Title::getTitleName() { + return m_titleName; +} + +std::string Title::getTitleAuthor() { + return m_titleAuthor; +} + +std::string Title::getTitleVersion() { + return m_titleVersion; +} + +u8* Title::getTitleIcon() { + return m_titleIcon; +} + +u64 Title::getTitleID() { + return m_titleID; +} + +std::vector Title::getUserIDs() { + return m_userIDs; +} + +void Title::addUserID(u128 userID) { + m_userIDs.push_back(userID); +} diff --git a/source/helpers/util.c b/source/helpers/util.c index a585f0ff..7e532373 100644 --- a/source/helpers/util.c +++ b/source/helpers/util.c @@ -1,122 +1,122 @@ -#include "helpers/util.h" - -#include -#include -#include - -#define MHz *1E6 - -static Service g_pmdmntService; -static u64 g_refCnt; - -static u64 g_uniquePadIds[2]; -static size_t g_uniquePadCnt; -static HidsysNotificationLedPattern g_patternOn, g_patternOff; - -Result amspmdmntInitialize(void) { - atomicIncrement64(&g_refCnt); - - if (g_pmdmntService.type != ServiceType_Uninitialized) - return 1; - - return smGetService(&g_pmdmntService, "pm:dmnt"); -} - -void amspmdmntExit(void) { - if (atomicDecrement64(&g_refCnt) == 0) { - serviceClose(&g_pmdmntService); - } -} - -bool isServiceRunning(const char *serviceName) { - Handle handle; - bool running = R_FAILED(smRegisterService(&handle, serviceName, false, 1)); - - svcCloseHandle(handle); - - if (!running) - smUnregisterService(serviceName); - - return running; -} - -void getCurrTimeString(char *buffer) { - time_t unixTime = time(NULL); - struct tm* time = localtime((const time_t*)&unixTime); - sprintf(buffer, "%02d:%02d", time->tm_hour, time->tm_min); -} - -void getCurrBatteryPercentage(char *buffer) { - u32 percents = 0; - psmGetBatteryChargePercentage(&percents); - sprintf(buffer, "%d%%", percents); -} - -void ledInit() { - hidsysGetUniquePadsFromNpad(hidGetHandheldMode() ? CONTROLLER_HANDHELD : CONTROLLER_PLAYER_1, g_uniquePadIds, 2, &g_uniquePadCnt); - - memset(&g_patternOn, 0x00, sizeof(HidsysNotificationLedPattern)); - memset(&g_patternOff, 0x00, sizeof(HidsysNotificationLedPattern)); - - g_patternOn.baseMiniCycleDuration = 0x0F; - g_patternOn.startIntensity = 0x0F; - g_patternOn.miniCycles[0].ledIntensity = 0x0F; - g_patternOn.miniCycles[0].transitionSteps = 0x0F; - g_patternOn.miniCycles[0].finalStepDuration = 0x0F; -} - -void setLedState(bool state) { - for(u8 i = 0; i < g_uniquePadCnt; i++) - hidsysSetNotificationLedPattern(state ? &g_patternOn : &g_patternOff, g_uniquePadIds[i]); -} - -void overclockSystem(bool enable) { - if (hosversionBefore(8, 0, 0)) { - pcvSetClockRate(PcvModule_CpuBus, enable ? 1785 MHz : 1020 MHz); // Set CPU clock - pcvSetClockRate(PcvModule_EMC, enable ? 1600 MHz : 1331 MHz); // Set memory clock - } else { - ClkrstSession clkrstSession; - clkrstOpenSession(&clkrstSession, PcvModuleId_CpuBus, 3); - clkrstSetClockRate(&clkrstSession, enable ? 1785 MHz : 1020 MHz); // Set CPU clock - clkrstCloseSession(&clkrstSession); - - clkrstOpenSession(&clkrstSession, PcvModuleId_EMC, 3); - clkrstSetClockRate(&clkrstSession, enable ? 1600 MHz : 1331 MHz); // Set memory clock - clkrstCloseSession(&clkrstSession); - } -} - -Result amspmdmntAtmosphereGetProcessHandle(Handle *out_processHandle) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 65000; - - Result rc = serviceIpcDispatch(&g_pmdmntService); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - - struct { - u64 magic; - u64 result; - } *resp; - - serviceIpcParse(&g_pmdmntService, &r, sizeof(*resp)); - resp = r.Raw; - - *out_processHandle = r.Handles[0]; - - rc = resp->result; - } - - return rc; +#include "helpers/util.h" + +#include +#include +#include + +#define MHz *1E6 + +static Service g_pmdmntService; +static u64 g_refCnt; + +static u64 g_uniquePadIds[2]; +static size_t g_uniquePadCnt; +static HidsysNotificationLedPattern g_patternOn, g_patternOff; + +Result amspmdmntInitialize(void) { + atomicIncrement64(&g_refCnt); + + if (serviceIsActive(&g_pmdmntService)) + return 1; + + return smGetService(&g_pmdmntService, "pm:dmnt"); +} + +void amspmdmntExit(void) { + if (atomicDecrement64(&g_refCnt) == 0) { + serviceClose(&g_pmdmntService); + } +} + +bool isServiceRunning(const char *serviceName) { + Handle handle; + bool running = R_FAILED(smRegisterService(&handle, serviceName, false, 1)); + + svcCloseHandle(handle); + + if (!running) + smUnregisterService(serviceName); + + return running; +} + +void getCurrTimeString(char *buffer) { + time_t unixTime = time(NULL); + struct tm* time = localtime((const time_t*)&unixTime); + sprintf(buffer, "%02d:%02d", time->tm_hour, time->tm_min); +} + +void getCurrBatteryPercentage(char *buffer) { + u32 percents = 0; + psmGetBatteryChargePercentage(&percents); + sprintf(buffer, "%d%%", percents); +} + +void ledInit() { + hidsysGetUniquePadsFromNpad(hidGetHandheldMode() ? CONTROLLER_HANDHELD : CONTROLLER_PLAYER_1, g_uniquePadIds, 2, &g_uniquePadCnt); + + memset(&g_patternOn, 0x00, sizeof(HidsysNotificationLedPattern)); + memset(&g_patternOff, 0x00, sizeof(HidsysNotificationLedPattern)); + + g_patternOn.baseMiniCycleDuration = 0x0F; + g_patternOn.startIntensity = 0x0F; + g_patternOn.miniCycles[0].ledIntensity = 0x0F; + g_patternOn.miniCycles[0].transitionSteps = 0x0F; + g_patternOn.miniCycles[0].finalStepDuration = 0x0F; +} + +void setLedState(bool state) { + for(u8 i = 0; i < g_uniquePadCnt; i++) + hidsysSetNotificationLedPattern(state ? &g_patternOn : &g_patternOff, g_uniquePadIds[i]); +} + +void overclockSystem(bool enable) { + if (hosversionBefore(8, 0, 0)) { + pcvSetClockRate(PcvModule_CpuBus, enable ? 1785 MHz : 1020 MHz); // Set CPU clock + pcvSetClockRate(PcvModule_EMC, enable ? 1600 MHz : 1331 MHz); // Set memory clock + } else { + ClkrstSession clkrstSession; + clkrstOpenSession(&clkrstSession, PcvModuleId_CpuBus, 3); + clkrstSetClockRate(&clkrstSession, enable ? 1785 MHz : 1020 MHz); // Set CPU clock + clkrstCloseSession(&clkrstSession); + + clkrstOpenSession(&clkrstSession, PcvModuleId_EMC, 3); + clkrstSetClockRate(&clkrstSession, enable ? 1600 MHz : 1331 MHz); // Set memory clock + clkrstCloseSession(&clkrstSession); + } +} + +Result amspmdmntAtmosphereGetProcessHandle(Handle *out_processHandle) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + + Result rc = serviceIpcDispatch(&g_pmdmntService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_pmdmntService, &r, sizeof(*resp)); + resp = r.Raw; + + *out_processHandle = r.Handles[0]; + + rc = resp->result; + } + + return rc; } \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 5dc7d710..cc44011e 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,370 +1,370 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "guis/gui.hpp" -#include "guis/gui_main.hpp" -#include "guis/gui_editor.hpp" -#include "guis/gui_tx_warning.hpp" -#include "guis/gui_cheats.hpp" -#include "guis/gui_about.hpp" -#include "guis/gui_guide.hpp" - -#include "helpers/title.hpp" - -#include "theme.h" -#include "helpers/util.h" -#include "helpers/config.hpp" - -#define LONG_PRESS_DELAY 2 -#define LONG_PRESS_ACTIVATION_DELAY 300 - -char* g_edizonPath; - -static int debugOutputFile; - -static bool updateThreadRunning = false; -static Mutex mutexCurrGui; -static Gui* currGui = nullptr; -static s64 inputTicker = 0; - -static u32 kheld = 0, kheldOld = 0; -static u32 kdown = 0; - -void initTitles() { - std::vector saveInfoList; - - _getSaveList(saveInfoList); - - s32 userCount = 0; - size_t foundUserCount = 0; - - accountGetUserCount(&userCount); - - u128 userIDs[userCount]; - accountListAllUsers(userIDs, userCount, &foundUserCount); - - for (auto saveInfo : saveInfoList) { - bool accountPresent = false; - - for (u32 i = 0; i < foundUserCount; i++) - if (userIDs[i] == saveInfo.userID) - accountPresent = true; - - if (!accountPresent) continue; - - if (Title::g_titles.find(saveInfo.titleID) == Title::g_titles.end()) - Title::g_titles.insert({(u64)saveInfo.titleID, new Title(saveInfo)}); - - Title::g_titles[saveInfo.titleID]->addUserID(saveInfo.userID); - - if (Account::g_accounts.find(saveInfo.userID) == Account::g_accounts.end()) { - Account *account = new Account(saveInfo.userID); - - if (!account->isInitialized()) { - delete account; - continue; - } - Account::g_accounts.insert(std::make_pair(static_cast(saveInfo.userID), account)); - } - } -} - -void update() { - while (updateThreadRunning) { - auto begin = std::chrono::steady_clock::now(); - - mutexLock(&mutexCurrGui); - if (currGui != nullptr) - currGui->update(); - mutexUnlock(&mutexCurrGui); - - if (kheld & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN)) inputTicker++; - else inputTicker = 0; - - svcSleepThread(1.0E6 - std::chrono::duration(std::chrono::steady_clock::now() - begin).count()); - } -} - -void createFolders() { - printf(EDIZON_DIR "/saves\n"); - mkdir("/switch", 0777); - mkdir(EDIZON_DIR "", 0777); - mkdir(EDIZON_DIR "/saves", 0777); - mkdir(EDIZON_DIR "/batch_saves", 0777); - mkdir(EDIZON_DIR "/restore", 0777); - mkdir(EDIZON_DIR "/editor", 0777); - mkdir(EDIZON_DIR "/editor/scripts", 0777); - mkdir(EDIZON_DIR "/editor/scripts/lib", 0777); - mkdir(EDIZON_DIR "/editor/scripts/lib/python3.5", 0777); -} - -void requestDraw() { - if (currGui != nullptr) - currGui->draw(); -} - -void serviceInitialize() { - setsysInitialize(); - socketInitializeDefault(); - nsInitialize(); - accountInitialize(); - plInitialize(); - psmInitialize(); - pminfoInitialize(); - pmdmntInitialize(); - romfsInit(); - hidsysInitialize(); - pcvInitialize(); - clkrstInitialize(); - ledInit(); - - curl_global_init(CURL_GLOBAL_ALL); - - u64 pid = 0; - u128 activeUser; - bool accountSelected; - Title::g_activeTitle = 0; - - pmdmntGetApplicationPid(&pid); - pminfoGetTitleId(&Title::g_activeTitle, pid); - - accountGetLastOpenedUser(&activeUser, &accountSelected); - - if (accountSelected) - Account::g_activeUser = activeUser; -} - -void serviceExit() { - setsysExit(); - socketExit(); - nsExit(); - accountExit(); - plExit(); - psmExit(); - pminfoExit(); - pmdmntExit(); - romfsExit(); - hidsysExit(); - pcvExit(); - clkrstExit(); - - curl_global_cleanup(); - - close(debugOutputFile); - -} - -void redirectStdio() { - nxlinkStdio(); - - debugOutputFile = open(EDIZON_DIR "/EdiZon.log", O_APPEND | O_WRONLY); - - if (debugOutputFile >= 0) { - fflush(stdout); - dup2(debugOutputFile, STDOUT_FILENO); - fflush(stderr); - dup2(debugOutputFile, STDERR_FILENO); - } -} - -int main(int argc, char** argv) { - void *haddr; - extern char *fake_heap_end; - - // Setup Heap for swkbd on applets - Result rc = svcSetHeapSize(&haddr, 0x10000000); - if (R_FAILED(rc)) - fatalSimple(0xDEAD); - fake_heap_end = (char*) haddr + 0x10000000; - - serviceInitialize(); - - redirectStdio(); - - framebufferCreate(&Gui::g_fb_obj, nwindowGetDefault(), 1280, 720, PIXEL_FORMAT_RGBA_8888, 2); - framebufferMakeLinear(&Gui::g_fb_obj); - - ColorSetId colorSetId; - setsysGetColorSetId(&colorSetId); - setTheme(colorSetId); - - initTitles(); - - printf("%s\n", EDIZON_DIR); - - createFolders(); - - Config::readConfig(); - - Gui::g_nextGui = GUI_MAIN; - - if (isServiceRunning("tx") && !isServiceRunning("rnx") && !Config::getConfig()->hideSX) - Gui::g_nextGui = GUI_TX_WARNING; - - g_edizonPath = new char[strlen(argv[0]) + 1]; - strcpy(g_edizonPath, argv[0] + 5); - - mutexInit(&mutexCurrGui); - - updateThreadRunning = true; - std::thread updateThread(update); - - - while (appletMainLoop()) { - hidScanInput(); - kheld = hidKeysHeld(CONTROLLER_P1_AUTO); - kdown = hidKeysDown(CONTROLLER_P1_AUTO); - - if (Gui::g_nextGui != GUI_INVALID) { - mutexLock(&mutexCurrGui); - if (currGui != nullptr) { - delete currGui; - currGui = nullptr; - } - - do { - gui_t nextGuiStart = Gui::g_nextGui; - switch (Gui::g_nextGui) { - case GUI_MAIN: - currGui = new GuiMain(); - break; - case GUI_EDITOR: - currGui = new GuiEditor(); - break; - case GUI_TX_WARNING: - currGui = new GuiTXWarning(); - break; - case GUI_CHEATS: - currGui = new GuiCheats(); - break; - case GUI_GUIDE: - currGui = new GuiGuide(); - break; - case GUI_ABOUT: - currGui = new GuiAbout(); - break; - - case GUI_INVALID: [[fallthrough]] - default: break; - } - if (nextGuiStart == Gui::g_nextGui) - Gui::g_nextGui = GUI_INVALID; - } while(Gui::g_nextGui != GUI_INVALID); - - mutexUnlock(&mutexCurrGui); - } - - if (currGui != nullptr) { - currGui->draw(); - - if (Gui::g_splashDisplayed) { - if (inputTicker > LONG_PRESS_ACTIVATION_DELAY && (inputTicker % LONG_PRESS_DELAY) == 0) { - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->onInput(kheld); - else if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->onInput(kheld); - else - currGui->onInput(kheld); - } else if (kdown || hidKeysUp(CONTROLLER_P1_AUTO)) { - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->onInput(kdown); - else if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->onInput(kdown); - else - currGui->onInput(kdown); - } - } - } - - if (kheld != kheldOld) { - inputTicker = 0; - } - - static touchPosition touchPosStart, touchPosCurr, touchPosOld; - static u8 touchCount, touchCountOld; - static bool touchHappend = false; - - touchCount = hidTouchCount(); - - if (touchCount > 0) - hidTouchRead(&touchPosCurr, 0); - - if(touchCount > 0 && touchCountOld == 0) - hidTouchRead(&touchPosStart, 0); - - if (abs(static_cast(touchPosStart.px - touchPosCurr.px)) < 10 && abs(static_cast(touchPosStart.py - touchPosCurr.py)) < 10) { - if (touchCount == 0 && touchCountOld > 0) { - touchHappend = true; - - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->onTouch(touchPosCurr); - else if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->onTouch(touchPosCurr); - else - currGui->onTouch(touchPosCurr); - } - } else if (touchCount > 0) { - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->onGesture(touchPosStart, touchPosCurr, false); - else if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->onGesture(touchPosStart, touchPosCurr, false); - else - currGui->onGesture(touchPosStart, touchPosCurr, false); - } - - if (touchCount == 0 && touchCountOld > 0 && !touchHappend) { - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->onGesture(touchPosStart, touchPosCurr, true); - else if (Gui::g_currListSelector != nullptr) - Gui::g_currListSelector->onGesture(touchPosStart, touchPosCurr, true); - else - currGui->onGesture(touchPosStart, touchPosCurr, true); - } - - touchCountOld = touchCount; - touchPosOld = touchPosCurr; - touchHappend = false; - - kheldOld = kheld; - - if (Gui::g_requestExit) { - if (Gui::g_currMessageBox == nullptr) - break; - } - } - - updateThreadRunning = false; - - updateThread.join(); - - delete[] g_edizonPath; - - for (auto it = Title::g_titles.begin(); it != Title::g_titles.end(); it++) - delete it->second; - - for (auto it = Account::g_accounts.begin(); it != Account::g_accounts.end(); it++) - delete it->second; - - Title::g_titles.clear(); - Account::g_accounts.clear(); - - if (currGui != nullptr) - delete currGui; - - framebufferClose(&Gui::g_fb_obj); - - serviceExit(); - - svcSetHeapSize(&haddr, ((u8*) envGetHeapOverrideAddr() + envGetHeapOverrideSize()) - (u8*) haddr); // clean up the heap - - return 0; -} +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "guis/gui.hpp" +#include "guis/gui_main.hpp" +#include "guis/gui_editor.hpp" +#include "guis/gui_tx_warning.hpp" +#include "guis/gui_cheats.hpp" +#include "guis/gui_about.hpp" +#include "guis/gui_guide.hpp" + +#include "helpers/title.hpp" + +#include "theme.h" +#include "helpers/util.h" +#include "helpers/config.hpp" + +#define LONG_PRESS_DELAY 2 +#define LONG_PRESS_ACTIVATION_DELAY 300 + +char* g_edizonPath; + +static int debugOutputFile; + +static bool updateThreadRunning = false; +static Mutex mutexCurrGui; +static Gui* currGui = nullptr; +static s64 inputTicker = 0; + +static u32 kheld = 0, kheldOld = 0; +static u32 kdown = 0; + +void initTitles() { + std::vector saveInfoList; + + _getSaveList(saveInfoList); + + s32 userCount = 0; + size_t foundUserCount = 0; + + accountGetUserCount(&userCount); + + u128 userIDs[userCount]; + accountListAllUsers(userIDs, userCount, &foundUserCount); + + for (auto saveInfo : saveInfoList) { + bool accountPresent = false; + + for (u32 i = 0; i < foundUserCount; i++) + if (userIDs[i] == saveInfo.userID) + accountPresent = true; + + if (!accountPresent) continue; + + if (Title::g_titles.find(saveInfo.titleID) == Title::g_titles.end()) + Title::g_titles.insert({(u64)saveInfo.titleID, new Title(saveInfo)}); + + Title::g_titles[saveInfo.titleID]->addUserID(saveInfo.userID); + + if (Account::g_accounts.find(saveInfo.userID) == Account::g_accounts.end()) { + Account *account = new Account(saveInfo.userID); + + if (!account->isInitialized()) { + delete account; + continue; + } + Account::g_accounts.insert(std::make_pair(static_cast(saveInfo.userID), account)); + } + } +} + +void update() { + while (updateThreadRunning) { + auto begin = std::chrono::steady_clock::now(); + + mutexLock(&mutexCurrGui); + if (currGui != nullptr) + currGui->update(); + mutexUnlock(&mutexCurrGui); + + if (kheld & (KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN)) inputTicker++; + else inputTicker = 0; + + svcSleepThread(1.0E6 - std::chrono::duration(std::chrono::steady_clock::now() - begin).count()); + } +} + +void createFolders() { + printf(EDIZON_DIR "/saves\n"); + mkdir("/switch", 0777); + mkdir(EDIZON_DIR "", 0777); + mkdir(EDIZON_DIR "/saves", 0777); + mkdir(EDIZON_DIR "/batch_saves", 0777); + mkdir(EDIZON_DIR "/restore", 0777); + mkdir(EDIZON_DIR "/editor", 0777); + mkdir(EDIZON_DIR "/editor/scripts", 0777); + mkdir(EDIZON_DIR "/editor/scripts/lib", 0777); + mkdir(EDIZON_DIR "/editor/scripts/lib/python3.5", 0777); +} + +void requestDraw() { + if (currGui != nullptr) + currGui->draw(); +} + +void serviceInitialize() { + setsysInitialize(); + socketInitializeDefault(); + nsInitialize(); + accountInitialize(); + plInitialize(); + psmInitialize(); + pminfoInitialize(); + pmdmntInitialize(); + romfsInit(); + hidsysInitialize(); + pcvInitialize(); + clkrstInitialize(); + ledInit(); + + curl_global_init(CURL_GLOBAL_ALL); + + u64 pid = 0; + u128 activeUser; + bool accountSelected; + Title::g_activeTitle = 0; + + pmdmntGetApplicationPid(&pid); + pminfoGetTitleId(&Title::g_activeTitle, pid); + + accountGetLastOpenedUser(&activeUser, &accountSelected); + + if (accountSelected) + Account::g_activeUser = activeUser; +} + +void serviceExit() { + setsysExit(); + socketExit(); + nsExit(); + accountExit(); + plExit(); + psmExit(); + pminfoExit(); + pmdmntExit(); + romfsExit(); + hidsysExit(); + pcvExit(); + clkrstExit(); + + curl_global_cleanup(); + + close(debugOutputFile); + +} + +void redirectStdio() { + nxlinkStdio(); + + debugOutputFile = open(EDIZON_DIR "/EdiZon.log", O_APPEND | O_WRONLY); + + if (debugOutputFile >= 0) { + fflush(stdout); + dup2(debugOutputFile, STDOUT_FILENO); + fflush(stderr); + dup2(debugOutputFile, STDERR_FILENO); + } +} + +int main(int argc, char** argv) { + void *haddr; + extern char *fake_heap_end; + + // Setup Heap for swkbd on applets + Result rc = svcSetHeapSize(&haddr, 0x10000000); + if (R_FAILED(rc)) + fatalSimple(0xDEAD); + fake_heap_end = (char*) haddr + 0x10000000; + + serviceInitialize(); + + redirectStdio(); + + framebufferCreate(&Gui::g_fb_obj, nwindowGetDefault(), 1280, 720, PIXEL_FORMAT_RGBA_8888, 2); + framebufferMakeLinear(&Gui::g_fb_obj); + + ColorSetId colorSetId; + setsysGetColorSetId(&colorSetId); + setTheme(colorSetId); + + initTitles(); + + printf("%s\n", EDIZON_DIR); + + createFolders(); + + Config::readConfig(); + + Gui::g_nextGui = GUI_MAIN; + + if (isServiceRunning("tx") && !isServiceRunning("rnx") && !Config::getConfig()->hideSX) + Gui::g_nextGui = GUI_TX_WARNING; + + g_edizonPath = new char[strlen(argv[0]) + 1]; + strcpy(g_edizonPath, argv[0] + 5); + + mutexInit(&mutexCurrGui); + + updateThreadRunning = true; + std::thread updateThread(update); + + + while (appletMainLoop()) { + hidScanInput(); + kheld = hidKeysHeld(CONTROLLER_P1_AUTO); + kdown = hidKeysDown(CONTROLLER_P1_AUTO); + + if (Gui::g_nextGui != GUI_INVALID) { + mutexLock(&mutexCurrGui); + if (currGui != nullptr) { + delete currGui; + currGui = nullptr; + } + + do { + gui_t nextGuiStart = Gui::g_nextGui; + switch (Gui::g_nextGui) { + case GUI_MAIN: + currGui = new GuiMain(); + break; + case GUI_EDITOR: + currGui = new GuiEditor(); + break; + case GUI_TX_WARNING: + currGui = new GuiTXWarning(); + break; + case GUI_CHEATS: + currGui = new GuiCheats(); + break; + case GUI_GUIDE: + currGui = new GuiGuide(); + break; + case GUI_ABOUT: + currGui = new GuiAbout(); + break; + + case GUI_INVALID: [[fallthrough]] + default: break; + } + if (nextGuiStart == Gui::g_nextGui) + Gui::g_nextGui = GUI_INVALID; + } while(Gui::g_nextGui != GUI_INVALID); + + mutexUnlock(&mutexCurrGui); + } + + if (currGui != nullptr) { + currGui->draw(); + + if (Gui::g_splashDisplayed) { + if (inputTicker > LONG_PRESS_ACTIVATION_DELAY && (inputTicker % LONG_PRESS_DELAY) == 0) { + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->onInput(kheld); + else if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->onInput(kheld); + else + currGui->onInput(kheld); + } else if (kdown || hidKeysUp(CONTROLLER_P1_AUTO)) { + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->onInput(kdown); + else if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->onInput(kdown); + else + currGui->onInput(kdown); + } + } + } + + if (kheld != kheldOld) { + inputTicker = 0; + } + + static touchPosition touchPosStart, touchPosCurr, touchPosOld; + static u8 touchCount, touchCountOld; + static bool touchHappend = false; + + touchCount = hidTouchCount(); + + if (touchCount > 0) + hidTouchRead(&touchPosCurr, 0); + + if(touchCount > 0 && touchCountOld == 0) + hidTouchRead(&touchPosStart, 0); + + if (abs(static_cast(touchPosStart.px - touchPosCurr.px)) < 10 && abs(static_cast(touchPosStart.py - touchPosCurr.py)) < 10) { + if (touchCount == 0 && touchCountOld > 0) { + touchHappend = true; + + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->onTouch(touchPosCurr); + else if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->onTouch(touchPosCurr); + else + currGui->onTouch(touchPosCurr); + } + } else if (touchCount > 0) { + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->onGesture(touchPosStart, touchPosCurr, false); + else if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->onGesture(touchPosStart, touchPosCurr, false); + else + currGui->onGesture(touchPosStart, touchPosCurr, false); + } + + if (touchCount == 0 && touchCountOld > 0 && !touchHappend) { + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->onGesture(touchPosStart, touchPosCurr, true); + else if (Gui::g_currListSelector != nullptr) + Gui::g_currListSelector->onGesture(touchPosStart, touchPosCurr, true); + else + currGui->onGesture(touchPosStart, touchPosCurr, true); + } + + touchCountOld = touchCount; + touchPosOld = touchPosCurr; + touchHappend = false; + + kheldOld = kheld; + + if (Gui::g_requestExit) { + if (Gui::g_currMessageBox == nullptr) + break; + } + } + + updateThreadRunning = false; + + updateThread.join(); + + delete[] g_edizonPath; + + for (auto it = Title::g_titles.begin(); it != Title::g_titles.end(); it++) + delete it->second; + + for (auto it = Account::g_accounts.begin(); it != Account::g_accounts.end(); it++) + delete it->second; + + Title::g_titles.clear(); + Account::g_accounts.clear(); + + if (currGui != nullptr) + delete currGui; + + framebufferClose(&Gui::g_fb_obj); + + serviceExit(); + + svcSetHeapSize(&haddr, ((u8*) envGetHeapOverrideAddr() + envGetHeapOverrideSize()) - (u8*) haddr); // clean up the heap + + return 0; +} diff --git a/source/scripting/interpreter.cpp b/source/scripting/interpreter.cpp index 3ed64845..14102b9d 100644 --- a/source/scripting/interpreter.cpp +++ b/source/scripting/interpreter.cpp @@ -1,85 +1,85 @@ -#include "scripting/interpreter.hpp" - -#include -#include - -#include "helpers/encoding.hpp" - -#define LLONG_MAX INT64_MAX -#define LLONG_MIN INT64_MIN -#include "lua.hpp" - -Interpreter::Interpreter() { - -} - -Interpreter::~Interpreter() { - -} - -void Interpreter::setSaveFileBuffer(u8 *buffer, size_t bufferSize, std::string encoding) { - std::vector utf8; - - std::transform(encoding.begin(), encoding.end(), encoding.begin(), ::tolower); - - if (encoding == "ascii") - m_encoding = ASCII; - else if (encoding == "utf-8") - m_encoding = UTF_8; - else if (encoding == "utf-16le") - m_encoding = UTF_16LE; - else if (encoding == "utf-16be") - m_encoding = UTF_16BE; - else printf("Lua init warning: Invalid encoding, using ASCII\n"); - - switch (m_encoding) { - case UTF_16BE: - utf8 = Encoding::uft16beToUtf8(buffer, bufferSize); - break; - case UTF_16LE: - utf8 = Encoding::uft16leToUtf8(buffer, bufferSize); - break; - case ASCII: [[fallthrough]] - case UTF_8: [[fallthrough]] - default: - utf8 = std::vector(buffer, buffer + bufferSize); - break; - } - - m_buffer.clear(); - - m_bufferSize = utf8.size(); - m_buffer.reserve(m_bufferSize); - - for (u32 i = 0; i < this->m_bufferSize; i++) - m_buffer[i] = utf8[i]; -} - -void Interpreter::setArgs(std::vector intArgs, std::vector strArgs) { - m_intArgs = intArgs; - m_strArgs = strArgs; -} - -double Interpreter::evaluateEquation(std::string equation, s64 value) { - lua_State *s = luaL_newstate(); - double ret; - std::string func = "function eval(value)\n"; - func += "return "; - func += equation; - func += "\nend"; - - luaL_dostring(s, func.c_str()); - lua_getglobal(s, "eval"); - lua_pushinteger(s, value); - if (lua_pcall(s, 1, 1, 0)) - printf("%s\n", lua_tostring(s, -1)); - - ret = lua_tonumber(s, -1); - - if (s != nullptr) { - lua_close(s); - s = nullptr; - } - - return ret; +#include "scripting/interpreter.hpp" + +#include +#include + +#include "helpers/encoding.hpp" + +#define LLONG_MAX INT64_MAX +#define LLONG_MIN INT64_MIN +#include "lua.hpp" + +Interpreter::Interpreter() { + +} + +Interpreter::~Interpreter() { + +} + +void Interpreter::setSaveFileBuffer(u8 *buffer, size_t bufferSize, std::string encoding) { + std::vector utf8; + + std::transform(encoding.begin(), encoding.end(), encoding.begin(), ::tolower); + + if (encoding == "ascii") + m_encoding = ASCII; + else if (encoding == "utf-8") + m_encoding = UTF_8; + else if (encoding == "utf-16le") + m_encoding = UTF_16LE; + else if (encoding == "utf-16be") + m_encoding = UTF_16BE; + else printf("Lua init warning: Invalid encoding, using ASCII\n"); + + switch (m_encoding) { + case UTF_16BE: + utf8 = Encoding::uft16beToUtf8(buffer, bufferSize); + break; + case UTF_16LE: + utf8 = Encoding::uft16leToUtf8(buffer, bufferSize); + break; + case ASCII: [[fallthrough]] + case UTF_8: [[fallthrough]] + default: + utf8 = std::vector(buffer, buffer + bufferSize); + break; + } + + m_buffer.clear(); + + m_bufferSize = utf8.size(); + m_buffer.reserve(m_bufferSize); + + for (u32 i = 0; i < this->m_bufferSize; i++) + m_buffer[i] = utf8[i]; +} + +void Interpreter::setArgs(std::vector intArgs, std::vector strArgs) { + m_intArgs = intArgs; + m_strArgs = strArgs; +} + +double Interpreter::evaluateEquation(std::string equation, s64 value) { + lua_State *s = luaL_newstate(); + double ret; + std::string func = "function eval(value)\n"; + func += "return "; + func += equation; + func += "\nend"; + + luaL_dostring(s, func.c_str()); + lua_getglobal(s, "eval"); + lua_pushinteger(s, value); + if (lua_pcall(s, 1, 1, 0)) + printf("%s\n", lua_tostring(s, -1)); + + ret = lua_tonumber(s, -1); + + if (s != nullptr) { + lua_close(s); + s = nullptr; + } + + return ret; } \ No newline at end of file diff --git a/source/scripting/lua_interpreter.cpp b/source/scripting/lua_interpreter.cpp index 34e14e98..3ca68428 100644 --- a/source/scripting/lua_interpreter.cpp +++ b/source/scripting/lua_interpreter.cpp @@ -1,268 +1,268 @@ -#include "scripting/lua_interpreter.hpp" - -#include -#include - -#include "helpers/encoding.hpp" - -int lua_getSaveFileBuffer(lua_State *state); -int lua_getStrArguments(lua_State *state); -int lua_getIntArguments(lua_State *state); - -typedef int (LuaInterpreter::*mem_func)(lua_State *s); - -template -int dispatch(lua_State *s) { - LuaInterpreter * ptr = *static_cast(lua_getextraspace(s)); - return ((*ptr).*func)(s); -} - -LuaInterpreter::LuaInterpreter() { - m_luaState = nullptr; - m_buffer.clear(); -} - -LuaInterpreter::~LuaInterpreter() { - if (m_luaState != nullptr) { - lua_close(m_luaState); - m_luaState = nullptr; - } - -} - -void LuaInterpreter::printError(lua_State *luaState) { - printf("%s\n", lua_tostring(luaState, -1)); -} - -bool LuaInterpreter::initialize(std::string filetype) { - m_luaState = luaL_newstate(); - - luaL_openlibs(m_luaState); - - *static_cast(lua_getextraspace(m_luaState)) = this; - - const luaL_Reg regs[] { - { "getSaveFileBuffer", &dispatch<&LuaInterpreter::lua_getSaveFileBuffer> }, - { "getSaveFileString", &dispatch<&LuaInterpreter::lua_getSaveFileString> }, - { "getStrArgs", &dispatch<&LuaInterpreter::lua_getStrArgs> }, - { "getIntArgs", &dispatch<&LuaInterpreter::lua_getIntArgs> }, - { nullptr, nullptr } - }; - - luaL_newlib(m_luaState, regs); - lua_setglobal(m_luaState, "edizon"); - - std::string path = EDIZON_DIR "/editor/scripts/"; - path += filetype; - path += ".lua"; - - luaL_loadfile(m_luaState, path.c_str()); - - if(lua_pcall(m_luaState, 0, 0, 0)) { - printError(m_luaState); - return false; - } - - printf("Lua interpreter initialized!\n"); - - return true; -} - -void LuaInterpreter::deinitialize() { - if (m_luaState != nullptr) { - lua_close(m_luaState); - m_luaState = nullptr; - } -} - -s64 LuaInterpreter::getValueFromSaveFile() { - s64 out; - - lua_getglobal(m_luaState, "getValueFromSaveFile"); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function getValueFromSaveFile!\n"); - } - - out = lua_tointeger(m_luaState, -1); - lua_pop(m_luaState, 1); - - return out; -} - -s64 LuaInterpreter::getDummyValue() { - s64 out; - - lua_getglobal(m_luaState, "getDummyValue"); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function getDummyValue!\n"); - } - - out = lua_tointeger(m_luaState, -1); - lua_pop(m_luaState, 1); - - return out; -} - - -std::string LuaInterpreter::getStringFromSaveFile() { - std::string out; - - lua_getglobal(m_luaState, "getStringFromSaveFile"); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function getStringFromSaveFile!\n"); - } - - out = lua_tostring(m_luaState, -1); - lua_pop(m_luaState, 1); - - return out; -} - -std::string LuaInterpreter::getDummyString() { - std::string out; - - lua_getglobal(m_luaState, "getDummyString"); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function getDummyString!\n"); - } - - out = lua_tostring(m_luaState, -1); - lua_pop(m_luaState, 1); - - return out; -} - -void LuaInterpreter::setValueInSaveFile(s64 value) { - lua_getglobal(m_luaState, "setValueInSaveFile"); - lua_pushinteger(m_luaState, value); - if (lua_pcall(m_luaState, 1, 0, 0)) { - printError(m_luaState); - printf("Error while calling Lua function setValueInSaveFile!\n"); - } -} - -void LuaInterpreter::setStringInSaveFile(std::string value) { - lua_getglobal(m_luaState, "setStringInSaveFile"); - lua_pushstring(m_luaState, value.c_str()); - if (lua_pcall(m_luaState, 1, 0, 0)) { - printError(m_luaState); - printf("Error while calling Lua function setStringInSaveFile!\n"); - } -} - -void LuaInterpreter::setDummyValue(s64 value) { - lua_getglobal(m_luaState, "setDummyValue"); - lua_pushinteger(m_luaState, value); - if (lua_pcall(m_luaState, 1, 0, 0)) { - printError(m_luaState); - printf("Error while calling Lua function setDummyValue!\n"); - } -} - -void LuaInterpreter::setDummyString(std::string value) { - lua_getglobal(m_luaState, "setDummyString"); - lua_pushstring(m_luaState, value.c_str()); - if (lua_pcall(m_luaState, 1, 0, 0)) { - printError(m_luaState); - printf("Error while calling Lua function setDummyString!\n"); - } -} - -void LuaInterpreter::getModifiedSaveFile(std::vector &buffer) { - std::vector encoded; - - lua_getglobal(m_luaState, "getModifiedSaveFile"); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function getModifiedSaveFile!\n"); - return; - } - - lua_pushnil(m_luaState); - - while (lua_next(m_luaState, 1)) { - encoded.push_back(lua_tointeger(m_luaState, -1)); - lua_pop(m_luaState, 1); - } - - lua_pop(m_luaState, 1); - - switch (m_encoding) { - case UTF_16BE: - buffer = Encoding::utf8ToUtf16be(&encoded[0], encoded.size()); - break; - case UTF_16LE: - buffer = Encoding::utf8ToUtf16le(&encoded[0], encoded.size()); - break; - case ASCII: [[fallthrough]] - case UTF_8: [[fallthrough]] - default: - buffer = encoded; - break; - } -} - -std::string LuaInterpreter::callFunction(std::string funcName) { - lua_getglobal(m_luaState, funcName.c_str()); - if (lua_pcall(m_luaState, 0, 1, 0)) { - printError(m_luaState); - printf("Error while calling Lua function %s!\n", funcName.c_str()); - } - - std::string out = lua_tostring(m_luaState, -1); - lua_pop(m_luaState, 1); - - return out; -} - -int LuaInterpreter::lua_getSaveFileBuffer(lua_State *state) { - lua_createtable(state, m_bufferSize, 0); - - for (u64 i = 0; i < m_bufferSize; i++) { - lua_pushinteger(state, i + 1); - lua_pushinteger(state, m_buffer[i]); - lua_settable(state, -3); - } - - return 1; -} - -int LuaInterpreter::lua_getSaveFileString(lua_State *state) { - std::string str = reinterpret_cast(&m_buffer[0]); - - str += '\x00'; - - str[m_bufferSize] = 0x00; - - lua_pushstring(state, str.c_str()); - - return 1; -} - -int LuaInterpreter::lua_getStrArgs(lua_State *state) { - lua_createtable(state, m_strArgs.size(), 0); - - for (u64 i = 0; i < m_strArgs.size(); i++) { - lua_pushinteger(state, i + 1); - lua_pushstring(state, m_strArgs[i].c_str()); - lua_settable(state, -3); - } - - return 1; -} - -int LuaInterpreter::lua_getIntArgs(lua_State *state) { - lua_createtable(state, m_intArgs.size(), 0); - - for (u64 i = 0; i < m_intArgs.size(); i++) { - lua_pushinteger(state, i + 1); - lua_pushinteger(state, m_intArgs[i]); - lua_settable(state, -3); - } - - return 1; -} +#include "scripting/lua_interpreter.hpp" + +#include +#include + +#include "helpers/encoding.hpp" + +int lua_getSaveFileBuffer(lua_State *state); +int lua_getStrArguments(lua_State *state); +int lua_getIntArguments(lua_State *state); + +typedef int (LuaInterpreter::*mem_func)(lua_State *s); + +template +int dispatch(lua_State *s) { + LuaInterpreter * ptr = *static_cast(lua_getextraspace(s)); + return ((*ptr).*func)(s); +} + +LuaInterpreter::LuaInterpreter() { + m_luaState = nullptr; + m_buffer.clear(); +} + +LuaInterpreter::~LuaInterpreter() { + if (m_luaState != nullptr) { + lua_close(m_luaState); + m_luaState = nullptr; + } + +} + +void LuaInterpreter::printError(lua_State *luaState) { + printf("%s\n", lua_tostring(luaState, -1)); +} + +bool LuaInterpreter::initialize(std::string filetype) { + m_luaState = luaL_newstate(); + + luaL_openlibs(m_luaState); + + *static_cast(lua_getextraspace(m_luaState)) = this; + + const luaL_Reg regs[] { + { "getSaveFileBuffer", &dispatch<&LuaInterpreter::lua_getSaveFileBuffer> }, + { "getSaveFileString", &dispatch<&LuaInterpreter::lua_getSaveFileString> }, + { "getStrArgs", &dispatch<&LuaInterpreter::lua_getStrArgs> }, + { "getIntArgs", &dispatch<&LuaInterpreter::lua_getIntArgs> }, + { nullptr, nullptr } + }; + + luaL_newlib(m_luaState, regs); + lua_setglobal(m_luaState, "edizon"); + + std::string path = EDIZON_DIR "/editor/scripts/"; + path += filetype; + path += ".lua"; + + luaL_loadfile(m_luaState, path.c_str()); + + if(lua_pcall(m_luaState, 0, 0, 0)) { + printError(m_luaState); + return false; + } + + printf("Lua interpreter initialized!\n"); + + return true; +} + +void LuaInterpreter::deinitialize() { + if (m_luaState != nullptr) { + lua_close(m_luaState); + m_luaState = nullptr; + } +} + +s64 LuaInterpreter::getValueFromSaveFile() { + s64 out; + + lua_getglobal(m_luaState, "getValueFromSaveFile"); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function getValueFromSaveFile!\n"); + } + + out = lua_tointeger(m_luaState, -1); + lua_pop(m_luaState, 1); + + return out; +} + +s64 LuaInterpreter::getDummyValue() { + s64 out; + + lua_getglobal(m_luaState, "getDummyValue"); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function getDummyValue!\n"); + } + + out = lua_tointeger(m_luaState, -1); + lua_pop(m_luaState, 1); + + return out; +} + + +std::string LuaInterpreter::getStringFromSaveFile() { + std::string out; + + lua_getglobal(m_luaState, "getStringFromSaveFile"); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function getStringFromSaveFile!\n"); + } + + out = lua_tostring(m_luaState, -1); + lua_pop(m_luaState, 1); + + return out; +} + +std::string LuaInterpreter::getDummyString() { + std::string out; + + lua_getglobal(m_luaState, "getDummyString"); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function getDummyString!\n"); + } + + out = lua_tostring(m_luaState, -1); + lua_pop(m_luaState, 1); + + return out; +} + +void LuaInterpreter::setValueInSaveFile(s64 value) { + lua_getglobal(m_luaState, "setValueInSaveFile"); + lua_pushinteger(m_luaState, value); + if (lua_pcall(m_luaState, 1, 0, 0)) { + printError(m_luaState); + printf("Error while calling Lua function setValueInSaveFile!\n"); + } +} + +void LuaInterpreter::setStringInSaveFile(std::string value) { + lua_getglobal(m_luaState, "setStringInSaveFile"); + lua_pushstring(m_luaState, value.c_str()); + if (lua_pcall(m_luaState, 1, 0, 0)) { + printError(m_luaState); + printf("Error while calling Lua function setStringInSaveFile!\n"); + } +} + +void LuaInterpreter::setDummyValue(s64 value) { + lua_getglobal(m_luaState, "setDummyValue"); + lua_pushinteger(m_luaState, value); + if (lua_pcall(m_luaState, 1, 0, 0)) { + printError(m_luaState); + printf("Error while calling Lua function setDummyValue!\n"); + } +} + +void LuaInterpreter::setDummyString(std::string value) { + lua_getglobal(m_luaState, "setDummyString"); + lua_pushstring(m_luaState, value.c_str()); + if (lua_pcall(m_luaState, 1, 0, 0)) { + printError(m_luaState); + printf("Error while calling Lua function setDummyString!\n"); + } +} + +void LuaInterpreter::getModifiedSaveFile(std::vector &buffer) { + std::vector encoded; + + lua_getglobal(m_luaState, "getModifiedSaveFile"); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function getModifiedSaveFile!\n"); + return; + } + + lua_pushnil(m_luaState); + + while (lua_next(m_luaState, 1)) { + encoded.push_back(lua_tointeger(m_luaState, -1)); + lua_pop(m_luaState, 1); + } + + lua_pop(m_luaState, 1); + + switch (m_encoding) { + case UTF_16BE: + buffer = Encoding::utf8ToUtf16be(&encoded[0], encoded.size()); + break; + case UTF_16LE: + buffer = Encoding::utf8ToUtf16le(&encoded[0], encoded.size()); + break; + case ASCII: [[fallthrough]] + case UTF_8: [[fallthrough]] + default: + buffer = encoded; + break; + } +} + +std::string LuaInterpreter::callFunction(std::string funcName) { + lua_getglobal(m_luaState, funcName.c_str()); + if (lua_pcall(m_luaState, 0, 1, 0)) { + printError(m_luaState); + printf("Error while calling Lua function %s!\n", funcName.c_str()); + } + + std::string out = lua_tostring(m_luaState, -1); + lua_pop(m_luaState, 1); + + return out; +} + +int LuaInterpreter::lua_getSaveFileBuffer(lua_State *state) { + lua_createtable(state, m_bufferSize, 0); + + for (u64 i = 0; i < m_bufferSize; i++) { + lua_pushinteger(state, i + 1); + lua_pushinteger(state, m_buffer[i]); + lua_settable(state, -3); + } + + return 1; +} + +int LuaInterpreter::lua_getSaveFileString(lua_State *state) { + std::string str = reinterpret_cast(&m_buffer[0]); + + str += '\x00'; + + str[m_bufferSize] = 0x00; + + lua_pushstring(state, str.c_str()); + + return 1; +} + +int LuaInterpreter::lua_getStrArgs(lua_State *state) { + lua_createtable(state, m_strArgs.size(), 0); + + for (u64 i = 0; i < m_strArgs.size(); i++) { + lua_pushinteger(state, i + 1); + lua_pushstring(state, m_strArgs[i].c_str()); + lua_settable(state, -3); + } + + return 1; +} + +int LuaInterpreter::lua_getIntArgs(lua_State *state) { + lua_createtable(state, m_intArgs.size(), 0); + + for (u64 i = 0; i < m_intArgs.size(); i++) { + lua_pushinteger(state, i + 1); + lua_pushinteger(state, m_intArgs[i]); + lua_settable(state, -3); + } + + return 1; +} diff --git a/source/scripting/python_interpreter.cpp b/source/scripting/python_interpreter.cpp index f26f2f99..24c39564 100644 --- a/source/scripting/python_interpreter.cpp +++ b/source/scripting/python_interpreter.cpp @@ -1,351 +1,351 @@ -#include "scripting/python_interpreter.hpp" - -#include -#include -#include - -#include "helpers/encoding.hpp" - -static void *python_extraspace; -static PyMethodDef *edizonMethods; -static PyModuleDef edizonModule; - -PythonInterpreter::PythonInterpreter() { - m_mainObject = nullptr; - m_buffer.clear(); -} - -PythonInterpreter::~PythonInterpreter() { - if (m_mainObject != nullptr) { - Py_Finalize(); - m_mainObject = nullptr; - } -} - -typedef PyObject *(PythonInterpreter::*mem_func)(PyObject *, PyObject *); - -template -PyObject *dispatch(PyObject *self, PyObject *args) { - PythonInterpreter *ptr = *reinterpret_cast(&python_extraspace); - return ((*ptr).*func)(self, args); -} - -PyMODINIT_FUNC PyInit_edizon() { - PyObject *m; - - m = PyModule_Create(&edizonModule); - - if (m == NULL) - return NULL; - - PyObject *error = PyErr_NewException("edizon.error", NULL, NULL); - - Py_INCREF(error); - - PyModule_AddObject(m, "error", error); - return m; -} - -bool PythonInterpreter::initialize(std::string filetype) { - python_extraspace = this; - m_buffer.clear(); - - edizonMethods = new PyMethodDef[5]; - edizonMethods[0] = { "getSaveFileBuffer", &dispatch<&PythonInterpreter::py_getSaveFileBuffer>, METH_NOARGS, "getSaveFileBuffer" }; - edizonMethods[1] = { "getSaveFileString", &dispatch<&PythonInterpreter::py_getSaveFileString>, METH_NOARGS, "getSaveFileString" }; - edizonMethods[2] = { "getStrArgs", &dispatch<&PythonInterpreter::py_getStrArgs>, METH_NOARGS, "getStrArgs" }; - edizonMethods[3] = { "getIntArgs", &dispatch<&PythonInterpreter::py_getIntArgs>, METH_NOARGS, "getIntArgs" }; - edizonMethods[4] = { NULL, NULL, 0, NULL }; - - edizonModule = { PyModuleDef_HEAD_INIT, "edizon", "EdiZon functions", 0, edizonMethods, NULL, NULL, NULL, NULL }; - - Py_NoSiteFlag = 1; - Py_IgnoreEnvironmentFlag = 1; - Py_NoUserSiteDirectory = 1; - - char cwd[256]; - getcwd(cwd, sizeof(cwd)); - - char *stripped_cwd = strchr(cwd, '/'); - if (stripped_cwd == NULL) stripped_cwd = cwd; - - Py_SetPythonHome(Py_DecodeLocale(EDIZON_DIR "/editor/scripts/", NULL)); - - PyImport_AppendInittab("edizon", PyInit_edizon); - - Py_Initialize(); - - PyObject *moduleMainString = PyUnicode_FromString("__main__"); - m_mainObject = PyImport_Import(moduleMainString); - - std::string path = EDIZON_DIR "/editor/scripts/"; - path += filetype; - path += ".py"; - - FILE *fp = fopen(path.c_str(), "r"); - - if (fp == nullptr) { - printf("Failed to load file\n"); - return false; - } - - if (PyRun_SimpleFileEx(fp, path.c_str(), true) != 0) { - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - return false; - } - - printf("Python interpreter initialized!\n"); - - return true; -} - -void PythonInterpreter::deinitialize() { - if (m_mainObject != nullptr) { - Py_Finalize(); - m_mainObject = nullptr; - } -} - -s64 PythonInterpreter::getValueFromSaveFile() { - PyObject *func = PyObject_GetAttrString(m_mainObject, "getValueFromSaveFile"); - - if (func == nullptr) { - printf("Failed to call python function getValueFromSaveFile!\n"); - return 0; - } - - PyObject *result = PyObject_CallObject(func, nullptr); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return 0; - - return PyLong_AsLong(result); -} - -s64 PythonInterpreter::getDummyValue() { - PyObject *func = PyObject_GetAttrString(m_mainObject, "getDummyValue"); - - if (func == nullptr) { - printf("Failed to call python function getDummyValue!\n"); - return 0; - } - PyObject *result = PyObject_CallObject(func, nullptr); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return 0; - - return PyLong_AsLong(result); -} - - -std::string PythonInterpreter::getStringFromSaveFile() { - PyObject *func = PyObject_GetAttrString(m_mainObject, "getStringFromSaveFile"); - - if (func == nullptr) { - printf("Failed to call python function getStringFromSaveFile!\n"); - return "NULL"; - } - PyObject *result = PyObject_CallObject(func, nullptr); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return "NULL"; - - return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); -} - -std::string PythonInterpreter::getDummyString() { - PyObject *func = PyObject_GetAttrString(m_mainObject, "getDummyString"); - - if (func == nullptr) { - printf("Failed to call python function getDummyString!\n"); - return "NULL"; - } - PyObject *result = PyObject_CallObject(func, nullptr); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return "NULL"; - - return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); -} - -void PythonInterpreter::setValueInSaveFile(s64 value) { - PyObject *func = PyObject_GetAttrString(m_mainObject, "setValueInSaveFile"); - - if (func == nullptr) { - printf("Failed to call python function setValueInSaveFile!\n"); - return; - } - - PyObject_CallObject(func, PyTuple_Pack(1, PyLong_FromLong(value))); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } -} - -void PythonInterpreter::setStringInSaveFile(std::string value) { - PyObject *func = PyObject_GetAttrString(m_mainObject, "setStringInSaveFile"); - - if (func == nullptr) { - printf("Failed to call python function setStringInSaveFile!\n"); - return; - } - - PyObject_CallObject(func, PyTuple_Pack(1, PyUnicode_FromString(value.c_str()))); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } -} - -void PythonInterpreter::setDummyValue(s64 value) { - PyObject *func = PyObject_GetAttrString(m_mainObject, "setDummyValue"); - - if (func == nullptr) { - printf("Failed to call python function setDummyValue!\n"); - return; - } - - PyObject_CallObject(func, PyTuple_Pack(1, PyLong_FromLong(value))); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } -} - -void PythonInterpreter::setDummyString(std::string value) { - PyObject *func = PyObject_GetAttrString(m_mainObject, "setDummyString"); - - if (func == nullptr) { - printf("Failed to call python function setDummyString!\n"); - return; - } - - PyObject_CallObject(func, PyTuple_Pack(1, PyUnicode_FromString(value.c_str()))); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } -} - -void PythonInterpreter::getModifiedSaveFile(std::vector &buffer) { - std::vector encoded; - - PyObject *func = PyObject_GetAttrString(m_mainObject, "getModifiedSaveFile"); - - if (func == nullptr) { - printf("Failed to call python function getModifiedSaveFile!\n"); - return; - } - - PyObject *result = PyObject_CallObject(func, nullptr); - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return; - - size_t size = PyByteArray_Size(result); - char *data = PyByteArray_AsString(result); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - encoded.reserve(size); - - for (u64 i = 0; i < size; i++) - encoded.push_back(data[i]); - - switch (m_encoding) { - case UTF_16BE: - buffer = Encoding::utf8ToUtf16be(&encoded[0], encoded.size()); - break; - case UTF_16LE: - buffer = Encoding::utf8ToUtf16le(&encoded[0], encoded.size()); - break; - case ASCII: [[fallthrough]] - case UTF_8: [[fallthrough]] - default: - buffer = encoded; - break; - } -} - -std::string PythonInterpreter::callFunction(std::string funcName) { - PyObject *func = PyObject_GetAttrString(m_mainObject, funcName.c_str()); - - if (func == nullptr) { - printf("Failed to call python function %s!\n", funcName.c_str()); - return ""; - } - - PyObject *result = PyObject_CallObject(func, nullptr); - - if (PyErr_Occurred() != nullptr) { - PyErr_Print(); - printf("\n"); - } - - if (result == nullptr) return ""; - - return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); -} - -PyObject *PythonInterpreter::py_getSaveFileBuffer(PyObject *self, PyObject *args) { - return PyByteArray_FromStringAndSize((char*)(&m_buffer[0]), m_bufferSize); -} - -PyObject *PythonInterpreter::py_getSaveFileString(PyObject *self, PyObject *args) { - std::string string((char*)(&m_buffer[0])); - - return PyUnicode_FromStringAndSize(string.c_str(), string.length()); -} - -PyObject *PythonInterpreter::py_getStrArgs(PyObject *self, PyObject *args) { - if (m_strArgs.empty()) return PyLong_FromLong(0); - - PyObject *strArgs = PyList_New(0); - - for (std::string arg : m_strArgs) - PyList_Append(strArgs, PyUnicode_FromString(arg.c_str())); - - return strArgs; -} - -PyObject *PythonInterpreter::py_getIntArgs(PyObject *self, PyObject *args) { - if (m_intArgs.empty()) return PyLong_FromLong(0); - - PyObject *intArgs = PyList_New(0); - - for (s64 arg : m_intArgs) - PyList_Append(intArgs, PyLong_FromLong(arg)); - - return intArgs; +#include "scripting/python_interpreter.hpp" + +#include +#include +#include + +#include "helpers/encoding.hpp" + +static void *python_extraspace; +static PyMethodDef *edizonMethods; +static PyModuleDef edizonModule; + +PythonInterpreter::PythonInterpreter() { + m_mainObject = nullptr; + m_buffer.clear(); +} + +PythonInterpreter::~PythonInterpreter() { + if (m_mainObject != nullptr) { + Py_Finalize(); + m_mainObject = nullptr; + } +} + +typedef PyObject *(PythonInterpreter::*mem_func)(PyObject *, PyObject *); + +template +PyObject *dispatch(PyObject *self, PyObject *args) { + PythonInterpreter *ptr = *reinterpret_cast(&python_extraspace); + return ((*ptr).*func)(self, args); +} + +PyMODINIT_FUNC PyInit_edizon() { + PyObject *m; + + m = PyModule_Create(&edizonModule); + + if (m == NULL) + return NULL; + + PyObject *error = PyErr_NewException("edizon.error", NULL, NULL); + + Py_INCREF(error); + + PyModule_AddObject(m, "error", error); + return m; +} + +bool PythonInterpreter::initialize(std::string filetype) { + python_extraspace = this; + m_buffer.clear(); + + edizonMethods = new PyMethodDef[5]; + edizonMethods[0] = { "getSaveFileBuffer", &dispatch<&PythonInterpreter::py_getSaveFileBuffer>, METH_NOARGS, "getSaveFileBuffer" }; + edizonMethods[1] = { "getSaveFileString", &dispatch<&PythonInterpreter::py_getSaveFileString>, METH_NOARGS, "getSaveFileString" }; + edizonMethods[2] = { "getStrArgs", &dispatch<&PythonInterpreter::py_getStrArgs>, METH_NOARGS, "getStrArgs" }; + edizonMethods[3] = { "getIntArgs", &dispatch<&PythonInterpreter::py_getIntArgs>, METH_NOARGS, "getIntArgs" }; + edizonMethods[4] = { NULL, NULL, 0, NULL }; + + edizonModule = { PyModuleDef_HEAD_INIT, "edizon", "EdiZon functions", 0, edizonMethods, NULL, NULL, NULL, NULL }; + + Py_NoSiteFlag = 1; + Py_IgnoreEnvironmentFlag = 1; + Py_NoUserSiteDirectory = 1; + + char cwd[256]; + getcwd(cwd, sizeof(cwd)); + + char *stripped_cwd = strchr(cwd, '/'); + if (stripped_cwd == NULL) stripped_cwd = cwd; + + Py_SetPythonHome(Py_DecodeLocale(EDIZON_DIR "/editor/scripts/", NULL)); + + PyImport_AppendInittab("edizon", PyInit_edizon); + + Py_Initialize(); + + PyObject *moduleMainString = PyUnicode_FromString("__main__"); + m_mainObject = PyImport_Import(moduleMainString); + + std::string path = EDIZON_DIR "/editor/scripts/"; + path += filetype; + path += ".py"; + + FILE *fp = fopen(path.c_str(), "r"); + + if (fp == nullptr) { + printf("Failed to load file\n"); + return false; + } + + if (PyRun_SimpleFileEx(fp, path.c_str(), true) != 0) { + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + return false; + } + + printf("Python interpreter initialized!\n"); + + return true; +} + +void PythonInterpreter::deinitialize() { + if (m_mainObject != nullptr) { + Py_Finalize(); + m_mainObject = nullptr; + } +} + +s64 PythonInterpreter::getValueFromSaveFile() { + PyObject *func = PyObject_GetAttrString(m_mainObject, "getValueFromSaveFile"); + + if (func == nullptr) { + printf("Failed to call python function getValueFromSaveFile!\n"); + return 0; + } + + PyObject *result = PyObject_CallObject(func, nullptr); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return 0; + + return PyLong_AsLong(result); +} + +s64 PythonInterpreter::getDummyValue() { + PyObject *func = PyObject_GetAttrString(m_mainObject, "getDummyValue"); + + if (func == nullptr) { + printf("Failed to call python function getDummyValue!\n"); + return 0; + } + PyObject *result = PyObject_CallObject(func, nullptr); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return 0; + + return PyLong_AsLong(result); +} + + +std::string PythonInterpreter::getStringFromSaveFile() { + PyObject *func = PyObject_GetAttrString(m_mainObject, "getStringFromSaveFile"); + + if (func == nullptr) { + printf("Failed to call python function getStringFromSaveFile!\n"); + return "NULL"; + } + PyObject *result = PyObject_CallObject(func, nullptr); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return "NULL"; + + return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); +} + +std::string PythonInterpreter::getDummyString() { + PyObject *func = PyObject_GetAttrString(m_mainObject, "getDummyString"); + + if (func == nullptr) { + printf("Failed to call python function getDummyString!\n"); + return "NULL"; + } + PyObject *result = PyObject_CallObject(func, nullptr); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return "NULL"; + + return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); +} + +void PythonInterpreter::setValueInSaveFile(s64 value) { + PyObject *func = PyObject_GetAttrString(m_mainObject, "setValueInSaveFile"); + + if (func == nullptr) { + printf("Failed to call python function setValueInSaveFile!\n"); + return; + } + + PyObject_CallObject(func, PyTuple_Pack(1, PyLong_FromLong(value))); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } +} + +void PythonInterpreter::setStringInSaveFile(std::string value) { + PyObject *func = PyObject_GetAttrString(m_mainObject, "setStringInSaveFile"); + + if (func == nullptr) { + printf("Failed to call python function setStringInSaveFile!\n"); + return; + } + + PyObject_CallObject(func, PyTuple_Pack(1, PyUnicode_FromString(value.c_str()))); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } +} + +void PythonInterpreter::setDummyValue(s64 value) { + PyObject *func = PyObject_GetAttrString(m_mainObject, "setDummyValue"); + + if (func == nullptr) { + printf("Failed to call python function setDummyValue!\n"); + return; + } + + PyObject_CallObject(func, PyTuple_Pack(1, PyLong_FromLong(value))); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } +} + +void PythonInterpreter::setDummyString(std::string value) { + PyObject *func = PyObject_GetAttrString(m_mainObject, "setDummyString"); + + if (func == nullptr) { + printf("Failed to call python function setDummyString!\n"); + return; + } + + PyObject_CallObject(func, PyTuple_Pack(1, PyUnicode_FromString(value.c_str()))); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } +} + +void PythonInterpreter::getModifiedSaveFile(std::vector &buffer) { + std::vector encoded; + + PyObject *func = PyObject_GetAttrString(m_mainObject, "getModifiedSaveFile"); + + if (func == nullptr) { + printf("Failed to call python function getModifiedSaveFile!\n"); + return; + } + + PyObject *result = PyObject_CallObject(func, nullptr); + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return; + + size_t size = PyByteArray_Size(result); + char *data = PyByteArray_AsString(result); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + encoded.reserve(size); + + for (u64 i = 0; i < size; i++) + encoded.push_back(data[i]); + + switch (m_encoding) { + case UTF_16BE: + buffer = Encoding::utf8ToUtf16be(&encoded[0], encoded.size()); + break; + case UTF_16LE: + buffer = Encoding::utf8ToUtf16le(&encoded[0], encoded.size()); + break; + case ASCII: [[fallthrough]] + case UTF_8: [[fallthrough]] + default: + buffer = encoded; + break; + } +} + +std::string PythonInterpreter::callFunction(std::string funcName) { + PyObject *func = PyObject_GetAttrString(m_mainObject, funcName.c_str()); + + if (func == nullptr) { + printf("Failed to call python function %s!\n", funcName.c_str()); + return ""; + } + + PyObject *result = PyObject_CallObject(func, nullptr); + + if (PyErr_Occurred() != nullptr) { + PyErr_Print(); + printf("\n"); + } + + if (result == nullptr) return ""; + + return std::string(PyBytes_AsString(PyUnicode_AsEncodedString(result, "utf-8", "~E~"))); +} + +PyObject *PythonInterpreter::py_getSaveFileBuffer(PyObject *self, PyObject *args) { + return PyByteArray_FromStringAndSize((char*)(&m_buffer[0]), m_bufferSize); +} + +PyObject *PythonInterpreter::py_getSaveFileString(PyObject *self, PyObject *args) { + std::string string((char*)(&m_buffer[0])); + + return PyUnicode_FromStringAndSize(string.c_str(), string.length()); +} + +PyObject *PythonInterpreter::py_getStrArgs(PyObject *self, PyObject *args) { + if (m_strArgs.empty()) return PyLong_FromLong(0); + + PyObject *strArgs = PyList_New(0); + + for (std::string arg : m_strArgs) + PyList_Append(strArgs, PyUnicode_FromString(arg.c_str())); + + return strArgs; +} + +PyObject *PythonInterpreter::py_getIntArgs(PyObject *self, PyObject *args) { + if (m_intArgs.empty()) return PyLong_FromLong(0); + + PyObject *intArgs = PyList_New(0); + + for (s64 arg : m_intArgs) + PyList_Append(intArgs, PyLong_FromLong(arg)); + + return intArgs; } \ No newline at end of file diff --git a/source/theme.c b/source/theme.c index f7969f80..4bb4f3f2 100644 --- a/source/theme.c +++ b/source/theme.c @@ -1,34 +1,34 @@ -#include "theme.h" - -#pragma GCC diagnostic ignored "-Wmissing-braces" - -theme_t currTheme; - -void setTheme(ColorSetId colorSetId) { - switch (colorSetId) { - case ColorSetId_Light: - currTheme = (theme_t) { - .textColor = RGBA8(0x00, 0x00, 0x00, 0xFF), - .backgroundColor = RGBA8(0xEA, 0xEA, 0xEA, 0xFF), - .highlightColor = RGBA8(0x27, 0xA3, 0xC7, 0xFF), - .selectedColor = RGBA8(0x50, 0x2D, 0xE4, 0xFF), - .separatorColor = RGBA8(0xA0, 0xA0, 0xA0, 0xFF), - .selectedButtonColor = RGBA8(0xFD, 0xFD, 0xFD, 0xFF), - .tooltipColor = RGBA8(0xFF, 0xFF, 0xFF, 0xFF), - .tooltipTextColor = RGBA8(0x08, 0xC4, 0xD0, 0xFF) - }; - break; - case ColorSetId_Dark: - currTheme = (theme_t) { - .textColor = RGBA8(0xFF, 0xFF, 0xFF, 0xFF), - .backgroundColor = RGBA8(0x31, 0x31, 0x31, 0xFF), - .highlightColor = RGBA8(0x27, 0xA3, 0xC7, 0xFF), - .selectedColor = RGBA8(0x59, 0xED, 0xC0, 0xFF), - .separatorColor = RGBA8(0x60, 0x60, 0x60, 0xFF), - .selectedButtonColor = RGBA8(0x25, 0x26, 0x2A, 0xFF), - .tooltipColor = RGBA8(0x60, 0x60, 0x60, 0xFF), - .tooltipTextColor = RGBA8(0x14, 0xBD, 0xFE, 0xFF) - }; - break; - } -} +#include "theme.h" + +#pragma GCC diagnostic ignored "-Wmissing-braces" + +theme_t currTheme; + +void setTheme(ColorSetId colorSetId) { + switch (colorSetId) { + case ColorSetId_Light: + currTheme = (theme_t) { + .textColor = RGBA8(0x00, 0x00, 0x00, 0xFF), + .backgroundColor = RGBA8(0xEA, 0xEA, 0xEA, 0xFF), + .highlightColor = RGBA8(0x27, 0xA3, 0xC7, 0xFF), + .selectedColor = RGBA8(0x50, 0x2D, 0xE4, 0xFF), + .separatorColor = RGBA8(0xA0, 0xA0, 0xA0, 0xFF), + .selectedButtonColor = RGBA8(0xFD, 0xFD, 0xFD, 0xFF), + .tooltipColor = RGBA8(0xFF, 0xFF, 0xFF, 0xFF), + .tooltipTextColor = RGBA8(0x08, 0xC4, 0xD0, 0xFF) + }; + break; + case ColorSetId_Dark: + currTheme = (theme_t) { + .textColor = RGBA8(0xFF, 0xFF, 0xFF, 0xFF), + .backgroundColor = RGBA8(0x31, 0x31, 0x31, 0xFF), + .highlightColor = RGBA8(0x27, 0xA3, 0xC7, 0xFF), + .selectedColor = RGBA8(0x59, 0xED, 0xC0, 0xFF), + .separatorColor = RGBA8(0x60, 0x60, 0x60, 0xFF), + .selectedButtonColor = RGBA8(0x25, 0x26, 0x2A, 0xFF), + .tooltipColor = RGBA8(0x60, 0x60, 0x60, 0xFF), + .tooltipTextColor = RGBA8(0x14, 0xBD, 0xFE, 0xFF) + }; + break; + } +} diff --git a/source/ui_elements/button.cpp b/source/ui_elements/button.cpp index 1f635136..744f7eb1 100644 --- a/source/ui_elements/button.cpp +++ b/source/ui_elements/button.cpp @@ -1,40 +1,40 @@ -#include "ui_elements/button.hpp" - -Button::Button(u16 x, u16 y, u16 w, u16 h, std::string text, buttonGroup_t *buttonGroup) -: m_x(x), m_y(y), m_w(w), m_h(h), m_text(text), m_buttonGroup(buttonGroup) { - m_inputActions = [](u32 kdown){ }; - - buttonGroup->buttons.push_back(this); -} - -Button::~Button() { - -} - -void Button::draw(Gui *gui) { - gui->drawShadow(m_x, m_y, m_w, m_h); - - if (m_buttonGroup->buttons[m_buttonGroup->selectedButton] == this) { - gui->drawRectangle(m_x - 5, m_y - 5, m_w + 10, m_h + 12, currTheme.highlightColor); - gui->drawShadow(m_x - 5, m_y - 5, m_w + 10, m_h + 10); - } - - gui->drawRectangle(m_x, m_y, m_w, m_h, currTheme.selectedColor); - - u32 textHeight; - gui->getTextDimensions(font20, m_text.c_str(), nullptr, &textHeight); - gui->drawTextAligned(font20, m_x + (m_w / 2), m_y + (m_h / 2) - (textHeight / 2), currTheme.backgroundColor, m_text.c_str(), ALIGNED_CENTER); -} - -void Button::onInput(u32 kdown) { - -} - -void Button::onTouch(touchPosition &touch) { - -} - -Button* Button::setInputAction(std::function inputActions) { - m_inputActions = inputActions; - return this; -} +#include "ui_elements/button.hpp" + +Button::Button(u16 x, u16 y, u16 w, u16 h, std::string text, buttonGroup_t *buttonGroup) +: m_x(x), m_y(y), m_w(w), m_h(h), m_text(text), m_buttonGroup(buttonGroup) { + m_inputActions = [](u32 kdown){ }; + + buttonGroup->buttons.push_back(this); +} + +Button::~Button() { + +} + +void Button::draw(Gui *gui) { + gui->drawShadow(m_x, m_y, m_w, m_h); + + if (m_buttonGroup->buttons[m_buttonGroup->selectedButton] == this) { + gui->drawRectangle(m_x - 5, m_y - 5, m_w + 10, m_h + 12, currTheme.highlightColor); + gui->drawShadow(m_x - 5, m_y - 5, m_w + 10, m_h + 10); + } + + gui->drawRectangle(m_x, m_y, m_w, m_h, currTheme.selectedColor); + + u32 textHeight; + gui->getTextDimensions(font20, m_text.c_str(), nullptr, &textHeight); + gui->drawTextAligned(font20, m_x + (m_w / 2), m_y + (m_h / 2) - (textHeight / 2), currTheme.backgroundColor, m_text.c_str(), ALIGNED_CENTER); +} + +void Button::onInput(u32 kdown) { + +} + +void Button::onTouch(touchPosition &touch) { + +} + +Button* Button::setInputAction(std::function inputActions) { + m_inputActions = inputActions; + return this; +} diff --git a/source/ui_elements/list_selector.cpp b/source/ui_elements/list_selector.cpp index 52294c6f..f9d8affc 100644 --- a/source/ui_elements/list_selector.cpp +++ b/source/ui_elements/list_selector.cpp @@ -1,123 +1,123 @@ -#include "ui_elements/list_selector.hpp" - -#include - -#include "guis/gui.hpp" - -float deltaOffset = 0; - -ListSelector::ListSelector(std::string title, std::string options, std::vector &listItems) : m_title(title), m_options(options), m_listItems(listItems) { - m_optionsWidth = 0; - m_optionsHeight = 0; - selectedItem = 0; - - yOffsetNext = 0; - yOffset = 0; - - startYOffset = 500; - startYOffsetNext = 0; -} - -ListSelector::~ListSelector() { - -} - -void ListSelector::update() { - deltaOffset = yOffsetNext - yOffset; - float scrollSpeed = deltaOffset / 64.0F; - float deltaOffsetStart = startYOffsetNext - startYOffset; - float scrollSpeedStart = deltaOffsetStart / 64.0F; - - yOffsetNext = 60 * selectedItem; - - if (yOffset != yOffsetNext) { - if (yOffsetNext > yOffset) - yOffset += ceil((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); - else - yOffset += floor((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); - } - - if (startYOffset != startYOffsetNext) { - if (startYOffsetNext > startYOffset) - startYOffset += ceil((abs(deltaOffsetStart) > scrollSpeedStart) ? scrollSpeedStart : deltaOffsetStart); - else - startYOffset += floor((abs(deltaOffsetStart) > scrollSpeedStart) ? scrollSpeedStart : deltaOffsetStart); - } - - if(startYOffset == startYOffsetNext && startYOffset == 500) - hide(); -} - -void ListSelector::draw(Gui *gui) { - gui->drawRectangled(0, 0, Gui::g_framebuffer_width, 220 + startYOffset, gui->makeColor(0x00, 0x00, 0x00, 0x80 * (1 - (startYOffset / 500.0F)))); - gui->drawRectangle(0, 220 + startYOffset, Gui::g_framebuffer_width, Gui::g_framebuffer_height - 120, currTheme.backgroundColor); - - if (m_listItems.size() != 0) { - for (s8 currItem = -1; currItem < (s8) m_listItems.size(); currItem++) - gui->drawRectangle(250, fmax(440 + 60 * currItem - yOffset, 220) + startYOffset + 45, Gui::g_framebuffer_width - 500, 1, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); - - gui->drawRectangled(220, 305 + 60 * 2 + deltaOffset - 5 + startYOffset, Gui::g_framebuffer_width - 440, 71, currTheme.highlightColor); - gui->drawRectangle(226, 305 + 60 * 2 + deltaOffset + startYOffset, Gui::g_framebuffer_width - 455, 61, currTheme.selectedButtonColor); - gui->drawShadow(220, 305 + 60 * 2 + deltaOffset - 5 + startYOffset, Gui::g_framebuffer_width - 440, 71); - - for (u8 currItem = 0; currItem < m_listItems.size(); currItem++) - gui->drawText(font20, 270, fmax(440 + 60 * currItem - yOffset, 220) + startYOffset, currTheme.textColor, m_listItems[currItem].c_str()); - - } else gui->drawText(font20, 300, 340 + 60 * 2 + startYOffset, currTheme.textColor, "No items present!"); - - gui->drawRectangle(0, 220 + startYOffset, Gui::g_framebuffer_width, 80, currTheme.backgroundColor); - gui->drawRectangle(0, Gui::g_framebuffer_height - 73 + startYOffset, Gui::g_framebuffer_width, 73, currTheme.backgroundColor); - gui->drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 300 + startYOffset, 1220, 1, currTheme.textColor); - gui->drawText(font24, 100, 240 + startYOffset, currTheme.textColor, m_title.c_str()); - - gui->drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73 + startYOffset, 1220, 1, currTheme.textColor); - gui->drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 50 + startYOffset, currTheme.textColor, m_options.c_str(), ALIGNED_RIGHT); -} - -ListSelector* ListSelector::setInputAction(std::function inputActions) { - m_inputActions = inputActions; - - return this; -} - -void ListSelector::onInput(u32 kdown) { - if (kdown & KEY_B) - startYOffsetNext = 500; - - if (kdown & KEY_UP) - if (selectedItem > 0) - selectedItem--; - - if (kdown & KEY_DOWN) - if (selectedItem < (static_cast(m_listItems.size() - 1))) - selectedItem++; - - m_inputActions(kdown, selectedItem); - -} - -void ListSelector::onTouch(touchPosition &touch) { - if(touch.px > 250 && touch.px < Gui::g_framebuffer_width - 250) { - if(touch.py > 325 && touch.py < (325 + 60 * 5)) { - s8 touchPos = ((touch.py - 325) / 60.0F); //325 + 60 * (currItem + 2) - - if((selectedItem + touchPos - 2) >= 0 && (selectedItem + touchPos - 2) <= (static_cast(m_listItems.size() - 1))) - selectedItem += (touchPos - 2); - } - } -} - -void ListSelector::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} - -void ListSelector::show() { - if (Gui::g_currListSelector != nullptr) - delete Gui::g_currListSelector; - - Gui::g_currListSelector = this; -} - -void ListSelector::hide() { - Gui::g_currListSelector = nullptr; -} +#include "ui_elements/list_selector.hpp" + +#include + +#include "guis/gui.hpp" + +float deltaOffset = 0; + +ListSelector::ListSelector(std::string title, std::string options, std::vector &listItems) : m_title(title), m_options(options), m_listItems(listItems) { + m_optionsWidth = 0; + m_optionsHeight = 0; + selectedItem = 0; + + yOffsetNext = 0; + yOffset = 0; + + startYOffset = 500; + startYOffsetNext = 0; +} + +ListSelector::~ListSelector() { + +} + +void ListSelector::update() { + deltaOffset = yOffsetNext - yOffset; + float scrollSpeed = deltaOffset / 64.0F; + float deltaOffsetStart = startYOffsetNext - startYOffset; + float scrollSpeedStart = deltaOffsetStart / 64.0F; + + yOffsetNext = 60 * selectedItem; + + if (yOffset != yOffsetNext) { + if (yOffsetNext > yOffset) + yOffset += ceil((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); + else + yOffset += floor((abs(deltaOffset) > scrollSpeed) ? scrollSpeed : deltaOffset); + } + + if (startYOffset != startYOffsetNext) { + if (startYOffsetNext > startYOffset) + startYOffset += ceil((abs(deltaOffsetStart) > scrollSpeedStart) ? scrollSpeedStart : deltaOffsetStart); + else + startYOffset += floor((abs(deltaOffsetStart) > scrollSpeedStart) ? scrollSpeedStart : deltaOffsetStart); + } + + if(startYOffset == startYOffsetNext && startYOffset == 500) + hide(); +} + +void ListSelector::draw(Gui *gui) { + gui->drawRectangled(0, 0, Gui::g_framebuffer_width, 220 + startYOffset, gui->makeColor(0x00, 0x00, 0x00, 0x80 * (1 - (startYOffset / 500.0F)))); + gui->drawRectangle(0, 220 + startYOffset, Gui::g_framebuffer_width, Gui::g_framebuffer_height - 120, currTheme.backgroundColor); + + if (m_listItems.size() != 0) { + for (s8 currItem = -1; currItem < (s8) m_listItems.size(); currItem++) + gui->drawRectangle(250, fmax(440 + 60 * currItem - yOffset, 220) + startYOffset + 45, Gui::g_framebuffer_width - 500, 1, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); + + gui->drawRectangled(220, 305 + 60 * 2 + deltaOffset - 5 + startYOffset, Gui::g_framebuffer_width - 440, 71, currTheme.highlightColor); + gui->drawRectangle(226, 305 + 60 * 2 + deltaOffset + startYOffset, Gui::g_framebuffer_width - 455, 61, currTheme.selectedButtonColor); + gui->drawShadow(220, 305 + 60 * 2 + deltaOffset - 5 + startYOffset, Gui::g_framebuffer_width - 440, 71); + + for (u8 currItem = 0; currItem < m_listItems.size(); currItem++) + gui->drawText(font20, 270, fmax(440 + 60 * currItem - yOffset, 220) + startYOffset, currTheme.textColor, m_listItems[currItem].c_str()); + + } else gui->drawText(font20, 300, 340 + 60 * 2 + startYOffset, currTheme.textColor, "No items present!"); + + gui->drawRectangle(0, 220 + startYOffset, Gui::g_framebuffer_width, 80, currTheme.backgroundColor); + gui->drawRectangle(0, Gui::g_framebuffer_height - 73 + startYOffset, Gui::g_framebuffer_width, 73, currTheme.backgroundColor); + gui->drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), 300 + startYOffset, 1220, 1, currTheme.textColor); + gui->drawText(font24, 100, 240 + startYOffset, currTheme.textColor, m_title.c_str()); + + gui->drawRectangle((u32)((Gui::g_framebuffer_width - 1220) / 2), Gui::g_framebuffer_height - 73 + startYOffset, 1220, 1, currTheme.textColor); + gui->drawTextAligned(font20, Gui::g_framebuffer_width - 100, Gui::g_framebuffer_height - 50 + startYOffset, currTheme.textColor, m_options.c_str(), ALIGNED_RIGHT); +} + +ListSelector* ListSelector::setInputAction(std::function inputActions) { + m_inputActions = inputActions; + + return this; +} + +void ListSelector::onInput(u32 kdown) { + if (kdown & KEY_B) + startYOffsetNext = 500; + + if (kdown & KEY_UP) + if (selectedItem > 0) + selectedItem--; + + if (kdown & KEY_DOWN) + if (selectedItem < (static_cast(m_listItems.size() - 1))) + selectedItem++; + + m_inputActions(kdown, selectedItem); + +} + +void ListSelector::onTouch(touchPosition &touch) { + if(touch.px > 250 && touch.px < Gui::g_framebuffer_width - 250) { + if(touch.py > 325 && touch.py < (325 + 60 * 5)) { + s8 touchPos = ((touch.py - 325) / 60.0F); //325 + 60 * (currItem + 2) + + if((selectedItem + touchPos - 2) >= 0 && (selectedItem + touchPos - 2) <= (static_cast(m_listItems.size() - 1))) + selectedItem += (touchPos - 2); + } + } +} + +void ListSelector::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} + +void ListSelector::show() { + if (Gui::g_currListSelector != nullptr) + delete Gui::g_currListSelector; + + Gui::g_currListSelector = this; +} + +void ListSelector::hide() { + Gui::g_currListSelector = nullptr; +} diff --git a/source/ui_elements/message_box.cpp b/source/ui_elements/message_box.cpp index 64b4b9f1..d496ac1d 100644 --- a/source/ui_elements/message_box.cpp +++ b/source/ui_elements/message_box.cpp @@ -1,121 +1,121 @@ -#include "ui_elements/message_box.hpp" - -#include - -#include "guis/gui.hpp" - -MessageBox::MessageBox(std::string message, MessageBox::MessageBoxOptions options) : m_message(message), m_options(options) { - m_selectedOption = 0; - m_progress = -1; - - m_selectionAction = [](s8 selection){}; - m_customDraw = [](Gui *gui, s16 x, s16 y){}; -} - -MessageBox::~MessageBox() { - -} - -MessageBox* MessageBox::setSelectionAction(std::function selectionAction) { - m_selectionAction = selectionAction; - - return this; -} - -MessageBox* MessageBox::setCustomDraw(std::function customDraw) { - m_customDraw = customDraw; - - return this; -} - - -void MessageBox::draw(Gui *gui) { - gui->drawRectangled(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, gui->makeColor(0x00, 0x00, 0x00, 0xA0)); - gui->drawRectangle(250, 180, Gui::g_framebuffer_width - 500, Gui::g_framebuffer_height - 360, currTheme.backgroundColor); - - gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 75, currTheme.textColor, m_message.c_str(), ALIGNED_CENTER); - - if (m_options == MessageBox::OKAY) { - gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); - gui->drawRectangled(245, Gui::g_framebuffer_height - 265, Gui::g_framebuffer_width - 490, 90, currTheme.highlightColor); - gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); - gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height - 237, currTheme.selectedColor, "Okay", ALIGNED_CENTER); - } - else if (m_options == MessageBox::YES_NO) { - gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); - gui->drawRectangled(245 + ((Gui::g_framebuffer_width - 490) / 2) * m_selectedOption, Gui::g_framebuffer_height - 265, (Gui::g_framebuffer_width - 490) / 2, 90, currTheme.highlightColor); - gui->drawRectangle(250, Gui::g_framebuffer_height - 260, (Gui::g_framebuffer_width - 500) / 2 - 6, 80, currTheme.selectedButtonColor); - gui->drawRectangle(250 + ((Gui::g_framebuffer_width - 490) / 2), Gui::g_framebuffer_height - 260, (Gui::g_framebuffer_width - 500) / 2 - 6, 80, currTheme.selectedButtonColor); - gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height - 237, currTheme.selectedColor, "No Yes", ALIGNED_CENTER); - } - - if (m_progress >= 0) { - gui->drawRectangle(350, Gui::g_framebuffer_height - 300, Gui::g_framebuffer_width - 700, 10, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); - gui->drawRectangle(350, Gui::g_framebuffer_height - 300, ((Gui::g_framebuffer_width - 700) / 100.0F) * m_progress, 10, currTheme.selectedColor); - } - - m_customDraw(gui, 250, 180); - -} - -void MessageBox::onInput(u32 kdown) { - if (m_options == MessageBox::OKAY) { - if (kdown & KEY_A || kdown & KEY_B) { - this->hide(); - } - } - else if (m_options == MessageBox::YES_NO) { - if (kdown & KEY_LEFT) - m_selectedOption = fmax(0, m_selectedOption - 1); - - if (kdown & KEY_RIGHT) - m_selectedOption = fmin(1, m_selectedOption + 1); - - if (kdown & KEY_A) { - m_selectionAction(m_selectedOption); - } - - if (kdown & KEY_B) { - m_selectionAction(0); - this->hide(); - } - } -} - -void MessageBox::onTouch(touchPosition &touch) { - if (m_options == MessageBox::OKAY) { - if (touch.px > 250 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < Gui::g_framebuffer_width - 250 && touch.py < Gui::g_framebuffer_height - 180) { - m_selectionAction(0); - this->hide(); - } - } else if (m_options == MessageBox::YES_NO) { - if (touch.px > 250 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < 250 + (Gui::g_framebuffer_width - 500) / 2 && touch.py < Gui::g_framebuffer_height - 180) { - m_selectionAction(0); - this->hide(); - } else if (touch.px > 250 + (Gui::g_framebuffer_width - 500) / 2 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < Gui::g_framebuffer_width - 250 && touch.py < Gui::g_framebuffer_height - 180) { - m_selectionAction(1); - this->hide(); - } - } -} - -void MessageBox::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { - -} - -void MessageBox::setProgress(s8 progress) { - this->m_progress = std::min((s8)100, progress); - requestDraw(); -} - - -void MessageBox::show() { - if (Gui::g_currMessageBox != nullptr) - delete Gui::g_currMessageBox; - - Gui::g_currMessageBox = this; -} - -void MessageBox::hide() { - Gui::g_currMessageBox = nullptr; -} +#include "ui_elements/message_box.hpp" + +#include + +#include "guis/gui.hpp" + +MessageBox::MessageBox(std::string message, MessageBox::MessageBoxOptions options) : m_message(message), m_options(options) { + m_selectedOption = 0; + m_progress = -1; + + m_selectionAction = [](s8 selection){}; + m_customDraw = [](Gui *gui, s16 x, s16 y){}; +} + +MessageBox::~MessageBox() { + +} + +MessageBox* MessageBox::setSelectionAction(std::function selectionAction) { + m_selectionAction = selectionAction; + + return this; +} + +MessageBox* MessageBox::setCustomDraw(std::function customDraw) { + m_customDraw = customDraw; + + return this; +} + + +void MessageBox::draw(Gui *gui) { + gui->drawRectangled(0, 0, Gui::g_framebuffer_width, Gui::g_framebuffer_height, gui->makeColor(0x00, 0x00, 0x00, 0xA0)); + gui->drawRectangle(250, 180, Gui::g_framebuffer_width - 500, Gui::g_framebuffer_height - 360, currTheme.backgroundColor); + + gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height / 2 - 75, currTheme.textColor, m_message.c_str(), ALIGNED_CENTER); + + if (m_options == MessageBox::OKAY) { + gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); + gui->drawRectangled(245, Gui::g_framebuffer_height - 265, Gui::g_framebuffer_width - 490, 90, currTheme.highlightColor); + gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); + gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height - 237, currTheme.selectedColor, "Okay", ALIGNED_CENTER); + } + else if (m_options == MessageBox::YES_NO) { + gui->drawRectangle(250, Gui::g_framebuffer_height - 260, Gui::g_framebuffer_width - 500, 80, currTheme.selectedButtonColor); + gui->drawRectangled(245 + ((Gui::g_framebuffer_width - 490) / 2) * m_selectedOption, Gui::g_framebuffer_height - 265, (Gui::g_framebuffer_width - 490) / 2, 90, currTheme.highlightColor); + gui->drawRectangle(250, Gui::g_framebuffer_height - 260, (Gui::g_framebuffer_width - 500) / 2 - 6, 80, currTheme.selectedButtonColor); + gui->drawRectangle(250 + ((Gui::g_framebuffer_width - 490) / 2), Gui::g_framebuffer_height - 260, (Gui::g_framebuffer_width - 500) / 2 - 6, 80, currTheme.selectedButtonColor); + gui->drawTextAligned(font20, Gui::g_framebuffer_width / 2, Gui::g_framebuffer_height - 237, currTheme.selectedColor, "No Yes", ALIGNED_CENTER); + } + + if (m_progress >= 0) { + gui->drawRectangle(350, Gui::g_framebuffer_height - 300, Gui::g_framebuffer_width - 700, 10, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); + gui->drawRectangle(350, Gui::g_framebuffer_height - 300, ((Gui::g_framebuffer_width - 700) / 100.0F) * m_progress, 10, currTheme.selectedColor); + } + + m_customDraw(gui, 250, 180); + +} + +void MessageBox::onInput(u32 kdown) { + if (m_options == MessageBox::OKAY) { + if (kdown & KEY_A || kdown & KEY_B) { + this->hide(); + } + } + else if (m_options == MessageBox::YES_NO) { + if (kdown & KEY_LEFT) + m_selectedOption = fmax(0, m_selectedOption - 1); + + if (kdown & KEY_RIGHT) + m_selectedOption = fmin(1, m_selectedOption + 1); + + if (kdown & KEY_A) { + m_selectionAction(m_selectedOption); + } + + if (kdown & KEY_B) { + m_selectionAction(0); + this->hide(); + } + } +} + +void MessageBox::onTouch(touchPosition &touch) { + if (m_options == MessageBox::OKAY) { + if (touch.px > 250 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < Gui::g_framebuffer_width - 250 && touch.py < Gui::g_framebuffer_height - 180) { + m_selectionAction(0); + this->hide(); + } + } else if (m_options == MessageBox::YES_NO) { + if (touch.px > 250 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < 250 + (Gui::g_framebuffer_width - 500) / 2 && touch.py < Gui::g_framebuffer_height - 180) { + m_selectionAction(0); + this->hide(); + } else if (touch.px > 250 + (Gui::g_framebuffer_width - 500) / 2 && touch.py > Gui::g_framebuffer_height - 260 && touch.px < Gui::g_framebuffer_width - 250 && touch.py < Gui::g_framebuffer_height - 180) { + m_selectionAction(1); + this->hide(); + } + } +} + +void MessageBox::onGesture(touchPosition startPosition, touchPosition endPosition, bool finish) { + +} + +void MessageBox::setProgress(s8 progress) { + this->m_progress = std::min((s8)100, progress); + requestDraw(); +} + + +void MessageBox::show() { + if (Gui::g_currMessageBox != nullptr) + delete Gui::g_currMessageBox; + + Gui::g_currMessageBox = this; +} + +void MessageBox::hide() { + Gui::g_currMessageBox = nullptr; +} diff --git a/source/ui_elements/snackbar.cpp b/source/ui_elements/snackbar.cpp index 4524b756..7326bb65 100644 --- a/source/ui_elements/snackbar.cpp +++ b/source/ui_elements/snackbar.cpp @@ -1,56 +1,56 @@ -#include "ui_elements/snackbar.hpp" - -#include "guis/gui.hpp" - -#include - -#define SNACKBAR_HEIGHT 100 -#define DISPLAY_TIME 3000 - -u16 yOffset = SNACKBAR_HEIGHT; -u16 yOffsetNext = 0; - -Snackbar::Snackbar(std::string text) : m_text(text) { - yOffset = SNACKBAR_HEIGHT; - yOffsetNext = 0; - m_isDead = false; -} - -Snackbar::~Snackbar() { - -} - -void Snackbar::show() { - m_displayTime = DISPLAY_TIME; - - if (Gui::g_currSnackbar != nullptr) - delete Gui::g_currSnackbar; - - Gui::g_currSnackbar = this; -} - -void Snackbar::update() { - float deltaOffset = yOffsetNext - yOffset; - float scrollSpeed = deltaOffset / 1024.0F; - - if (yOffset != yOffsetNext) { - if (yOffsetNext > yOffset) - yOffset += ceil((abs(deltaOffset) > abs(scrollSpeed)) ? scrollSpeed : deltaOffset); - else - yOffset += floor((abs(deltaOffset) > abs(scrollSpeed)) ? scrollSpeed : deltaOffset); - } - - if (m_displayTime > 0) m_displayTime--; - else yOffsetNext = SNACKBAR_HEIGHT; - - if (yOffset == SNACKBAR_HEIGHT) m_isDead = true; -} - -void Snackbar::draw(Gui *gui) { - gui->drawRectangle(0, (Gui::g_framebuffer_height - SNACKBAR_HEIGHT) + yOffset, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.textColor); - gui->drawText(font20, 50, (Gui::g_framebuffer_height - SNACKBAR_HEIGHT) + 35 + yOffset, currTheme.backgroundColor, m_text.c_str()); -} - -bool Snackbar::isDead() { - return m_isDead; -} +#include "ui_elements/snackbar.hpp" + +#include "guis/gui.hpp" + +#include + +#define SNACKBAR_HEIGHT 100 +#define DISPLAY_TIME 3000 + +u16 yOffset = SNACKBAR_HEIGHT; +u16 yOffsetNext = 0; + +Snackbar::Snackbar(std::string text) : m_text(text) { + yOffset = SNACKBAR_HEIGHT; + yOffsetNext = 0; + m_isDead = false; +} + +Snackbar::~Snackbar() { + +} + +void Snackbar::show() { + m_displayTime = DISPLAY_TIME; + + if (Gui::g_currSnackbar != nullptr) + delete Gui::g_currSnackbar; + + Gui::g_currSnackbar = this; +} + +void Snackbar::update() { + float deltaOffset = yOffsetNext - yOffset; + float scrollSpeed = deltaOffset / 1024.0F; + + if (yOffset != yOffsetNext) { + if (yOffsetNext > yOffset) + yOffset += ceil((abs(deltaOffset) > abs(scrollSpeed)) ? scrollSpeed : deltaOffset); + else + yOffset += floor((abs(deltaOffset) > abs(scrollSpeed)) ? scrollSpeed : deltaOffset); + } + + if (m_displayTime > 0) m_displayTime--; + else yOffsetNext = SNACKBAR_HEIGHT; + + if (yOffset == SNACKBAR_HEIGHT) m_isDead = true; +} + +void Snackbar::draw(Gui *gui) { + gui->drawRectangle(0, (Gui::g_framebuffer_height - SNACKBAR_HEIGHT) + yOffset, Gui::g_framebuffer_width, Gui::g_framebuffer_height, currTheme.textColor); + gui->drawText(font20, 50, (Gui::g_framebuffer_height - SNACKBAR_HEIGHT) + 35 + yOffset, currTheme.backgroundColor, m_text.c_str()); +} + +bool Snackbar::isDead() { + return m_isDead; +} diff --git a/source/update_manager.cpp b/source/update_manager.cpp index 28c5450d..71aa441f 100644 --- a/source/update_manager.cpp +++ b/source/update_manager.cpp @@ -1,259 +1,259 @@ -#include "update_manager.hpp" - -#include "guis/gui.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "helpers/util.h" - -#include "json.hpp" - -using json = nlohmann::json; - -extern char* g_edizonPath; - -static CURL *curl; - -UpdateManager::UpdateManager() { - curl = curl_easy_init(); - - if (!curl) - printf("Curl initialization failed!\n"); -} - -UpdateManager::~UpdateManager() { - curl_easy_cleanup(curl); -} - -static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userp){ - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; -} - -static size_t writeToFile(void *ptr, size_t size, size_t nmemb, FILE *stream) { - size_t written = fwrite(ptr, size, nmemb, stream); - return written; -} - -void deleteFile(std::string path) { - printf("Deleting %s.\n", path.c_str()); - - remove(path.c_str()); - -} - -void mkPath(std::string s, mode_t mode) { - char *str = new char[s.size() + 2]; - strcpy(str, s.c_str()); - strcat(str, "/"); - - char *delim = strchr(str + 1, '/'); - - do { - *delim = '\0'; - - mkdir(str, mode); - - *delim = '/'; - delim = strchr(delim + 1, '/'); - } while (delim != nullptr); -} - -char* barray2hexstr (const unsigned char* data, size_t datalen) { - size_t final_len = datalen * 2; - char* chrs = (char *) malloc((final_len + 1) * sizeof(*chrs)); - unsigned int j = 0; - - for(j = 0; j < datalen; j++) { - chrs[2 * j] = (data[j] >> 4) + 48; - chrs[2 * j + 1] = (data[j] & 15 ) + 48; - if (chrs[2 * j] > 57) chrs[2 * j] += 7; - if (chrs[2 * j + 1] > 57) chrs[2 * j + 1] += 7; - } - chrs[2 * j] = '\0'; - - return chrs; -} - -char *dirname (char *path) { - static const char dot[] = "."; - char *last_slash; - - last_slash = path != NULL ? strrchr (path, '/') : NULL; - - if (last_slash == path) - ++last_slash; - else if (last_slash != NULL && last_slash[1] == '\0') - last_slash = (char*)memchr (path, last_slash - path, '/'); - - if (last_slash != NULL) - last_slash[0] = '\0'; - else - path = (char *) dot; - - return path; -} - -void updateFile(std::string path) { - printf("Updating %s.\n", path.c_str()); - - std::string url = EDIZON_URL; - url.append(path); - - FILE* fp; - - char *cPath = new char[path.length() + 1]; - strcpy(cPath, path.c_str()); - - mkPath(dirname(cPath), 0777); - - fp = fopen(path.c_str(), "wb"); - - delete[] cPath; - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToFile); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - - CURLcode res = curl_easy_perform(curl); - - fclose(fp); - - if (res != CURLE_OK) { - printf("Update download CURL perform failed: %s\n", curl_easy_strerror(res)); - deleteFile(path.c_str()); - } -} - -void deleteRemovedFiles(char *path) { - DIR* dir; - struct dirent *ent; - if((dir=opendir(path)) != NULL){ - while (( ent = readdir(dir)) != NULL){ - if(ent->d_type == DT_DIR && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0){ - printf("%s\n", ent->d_name); - deleteRemovedFiles(ent->d_name); - } - } - closedir(dir); - } -} - -Updates UpdateManager::checkUpdate() { - if (!curl) - return ERROR; - - CURLcode res; - std::string str; - - curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/versionlist.php"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToString); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &str); - - res = curl_easy_perform(curl); - - if (res != CURLE_OK) { - printf("Version check CURL perform failed: %s\n", curl_easy_strerror(res)); - return ERROR; - } - - if (str.compare(0, 1, "{") != 0) { - printf("Invalid downloaded update file!\n"); - return ERROR; - } - - json remote = json::parse(str); - Updates updatedFile = NONE; - - u32 fileCnt = std::distance(remote.begin(), remote.end()); - u32 progress = 0; - - for (json::iterator iter = remote.begin(); iter != remote.end(); ++iter) { - FILE *fp = fopen(iter.key().c_str(), "rb"); - - progress++; - - if (Gui::g_currMessageBox != nullptr && progress % 10 == 0) - Gui::g_currMessageBox->setProgress((static_cast(progress) / fileCnt) * 100); - - if (fp != nullptr) { - char *content; - size_t fileSize; - u8 fileHash[0x20]; - - fseek(fp, 0, SEEK_END); - fileSize = ftell(fp); - rewind(fp); - - content = new char[fileSize]; - - fread(content, 1, fileSize, fp); - - Sha256Context shaCtx; - - sha256ContextCreate(&shaCtx); - sha256ContextUpdate(&shaCtx, (u8 *)content, fileSize); - sha256ContextGetHash(&shaCtx, fileHash); - - delete[] content; - fclose(fp); - - char *fileHashStr = barray2hexstr(fileHash, 0x20); - - if (strcmp(fileHashStr, iter.value().get().c_str()) == 0) { - free(fileHashStr); - continue; - } - - free(fileHashStr); - } - - updateFile(iter.key()); - - if (updatedFile == NONE) - updatedFile = EDITOR; - - if (iter.key().find("EdiZon.nro") != std::string::npos) - updatedFile = EDIZON; - } - - for (auto p : std::filesystem::recursive_directory_iterator(EDIZON_DIR "/editor")) { - if (remote[p.path().c_str()] == nullptr) { - if (!p.is_directory()) { - deleteFile(p.path().c_str()); - - if (updatedFile == NONE) - updatedFile = EDITOR; - } - } - } - - for (auto p : std::filesystem::recursive_directory_iterator("/atmosphere/titles")) { - std::string currPath = p.path().c_str(); - if (remote[currPath] == nullptr) { - if (!p.is_directory() && currPath.find("cheats") != std::string::npos) { - deleteFile(currPath); - - if (updatedFile == NONE) - updatedFile = EDITOR; - } - } - } - - return updatedFile; -} +#include "update_manager.hpp" + +#include "guis/gui.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "helpers/util.h" + +#include "json.hpp" + +using json = nlohmann::json; + +extern char* g_edizonPath; + +static CURL *curl; + +UpdateManager::UpdateManager() { + curl = curl_easy_init(); + + if (!curl) + printf("Curl initialization failed!\n"); +} + +UpdateManager::~UpdateManager() { + curl_easy_cleanup(curl); +} + +static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userp){ + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} + +static size_t writeToFile(void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t written = fwrite(ptr, size, nmemb, stream); + return written; +} + +void deleteFile(std::string path) { + printf("Deleting %s.\n", path.c_str()); + + remove(path.c_str()); + +} + +void mkPath(std::string s, mode_t mode) { + char *str = new char[s.size() + 2]; + strcpy(str, s.c_str()); + strcat(str, "/"); + + char *delim = strchr(str + 1, '/'); + + do { + *delim = '\0'; + + mkdir(str, mode); + + *delim = '/'; + delim = strchr(delim + 1, '/'); + } while (delim != nullptr); +} + +char* barray2hexstr (const unsigned char* data, size_t datalen) { + size_t final_len = datalen * 2; + char* chrs = (char *) malloc((final_len + 1) * sizeof(*chrs)); + unsigned int j = 0; + + for(j = 0; j < datalen; j++) { + chrs[2 * j] = (data[j] >> 4) + 48; + chrs[2 * j + 1] = (data[j] & 15 ) + 48; + if (chrs[2 * j] > 57) chrs[2 * j] += 7; + if (chrs[2 * j + 1] > 57) chrs[2 * j + 1] += 7; + } + chrs[2 * j] = '\0'; + + return chrs; +} + +char *dirname (char *path) { + static const char dot[] = "."; + char *last_slash; + + last_slash = path != NULL ? strrchr (path, '/') : NULL; + + if (last_slash == path) + ++last_slash; + else if (last_slash != NULL && last_slash[1] == '\0') + last_slash = (char*)memchr (path, last_slash - path, '/'); + + if (last_slash != NULL) + last_slash[0] = '\0'; + else + path = (char *) dot; + + return path; +} + +void updateFile(std::string path) { + printf("Updating %s.\n", path.c_str()); + + std::string url = EDIZON_URL; + url.append(path); + + FILE* fp; + + char *cPath = new char[path.length() + 1]; + strcpy(cPath, path.c_str()); + + mkPath(dirname(cPath), 0777); + + fp = fopen(path.c_str(), "wb"); + + delete[] cPath; + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToFile); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + + CURLcode res = curl_easy_perform(curl); + + fclose(fp); + + if (res != CURLE_OK) { + printf("Update download CURL perform failed: %s\n", curl_easy_strerror(res)); + deleteFile(path.c_str()); + } +} + +void deleteRemovedFiles(char *path) { + DIR* dir; + struct dirent *ent; + if((dir=opendir(path)) != NULL){ + while (( ent = readdir(dir)) != NULL){ + if(ent->d_type == DT_DIR && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0){ + printf("%s\n", ent->d_name); + deleteRemovedFiles(ent->d_name); + } + } + closedir(dir); + } +} + +Updates UpdateManager::checkUpdate() { + if (!curl) + return ERROR; + + CURLcode res; + std::string str; + + curl_easy_setopt(curl, CURLOPT_URL, EDIZON_URL "/versionlist.php"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToString); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &str); + + res = curl_easy_perform(curl); + + if (res != CURLE_OK) { + printf("Version check CURL perform failed: %s\n", curl_easy_strerror(res)); + return ERROR; + } + + if (str.compare(0, 1, "{") != 0) { + printf("Invalid downloaded update file!\n"); + return ERROR; + } + + json remote = json::parse(str); + Updates updatedFile = NONE; + + u32 fileCnt = std::distance(remote.begin(), remote.end()); + u32 progress = 0; + + for (json::iterator iter = remote.begin(); iter != remote.end(); ++iter) { + FILE *fp = fopen(iter.key().c_str(), "rb"); + + progress++; + + if (Gui::g_currMessageBox != nullptr && progress % 10 == 0) + Gui::g_currMessageBox->setProgress((static_cast(progress) / fileCnt) * 100); + + if (fp != nullptr) { + char *content; + size_t fileSize; + u8 fileHash[0x20]; + + fseek(fp, 0, SEEK_END); + fileSize = ftell(fp); + rewind(fp); + + content = new char[fileSize]; + + fread(content, 1, fileSize, fp); + + Sha256Context shaCtx; + + sha256ContextCreate(&shaCtx); + sha256ContextUpdate(&shaCtx, (u8 *)content, fileSize); + sha256ContextGetHash(&shaCtx, fileHash); + + delete[] content; + fclose(fp); + + char *fileHashStr = barray2hexstr(fileHash, 0x20); + + if (strcmp(fileHashStr, iter.value().get().c_str()) == 0) { + free(fileHashStr); + continue; + } + + free(fileHashStr); + } + + updateFile(iter.key()); + + if (updatedFile == NONE) + updatedFile = EDITOR; + + if (iter.key().find("EdiZon.nro") != std::string::npos) + updatedFile = EDIZON; + } + + for (auto p : std::filesystem::recursive_directory_iterator(EDIZON_DIR "/editor")) { + if (remote[p.path().c_str()] == nullptr) { + if (!p.is_directory()) { + deleteFile(p.path().c_str()); + + if (updatedFile == NONE) + updatedFile = EDITOR; + } + } + } + + for (auto p : std::filesystem::recursive_directory_iterator("/atmosphere/titles")) { + std::string currPath = p.path().c_str(); + if (remote[currPath] == nullptr) { + if (!p.is_directory() && currPath.find("cheats") != std::string::npos) { + deleteFile(currPath); + + if (updatedFile == NONE) + updatedFile = EDITOR; + } + } + } + + return updatedFile; +} diff --git a/source/upload_manager.cpp b/source/upload_manager.cpp index d2842860..c0ddaecf 100644 --- a/source/upload_manager.cpp +++ b/source/upload_manager.cpp @@ -1,182 +1,182 @@ -#include "upload_manager.hpp" - -#include "zipper.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "guis/gui.hpp" -#include "json.hpp" - -using json = nlohmann::json; - -UploadManager::UploadManager() { - m_curl = curl_easy_init(); - - if (!m_curl) - printf("Curl initialization failed!\n"); -} - -UploadManager::~UploadManager() { - curl_easy_cleanup(m_curl); -} - -size_t writefunc(void *ptr, size_t size, size_t nmemb, std::string* s) { - *s += reinterpret_cast(ptr); - return size*nmemb; -} - -std::vector listFiles(const std::string &path) { - std::vector paths; - if (auto dir = opendir(path.c_str())) { - while (auto f = readdir(dir)) { - if (!f->d_name || f->d_name[0] == '.') continue; - if (f->d_type == DT_DIR) - listFiles(path + f->d_name + "/"); - - if (f->d_type == DT_REG) - paths.push_back(path + "/" + f->d_name); - } - closedir(dir); - } - - return paths; -} - -static int xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->setProgress(50.0F + ((ulnow / static_cast(ultotal)) * 100) / 2.0F); - - hidScanInput(); - - return hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B; -} - -std::string UploadManager::upload(std::string path, std::string fileName, Title *title, std::string hash) { - if (gethostid() == INADDR_LOOPBACK) return ""; - - std::vector zipData; - std::string returnData; - - std::vector filePaths; - std::filesystem::recursive_directory_iterator end; - for (std::filesystem::recursive_directory_iterator it(path); it != end; ++it) - if (!it->is_directory()) - filePaths.push_back(it->path().c_str()); - - if (!this->zip(filePaths, &zipData)) return ""; - - curl_mime *mime; - curl_mimepart *part; - - mime = curl_mime_init(m_curl); - part = curl_mime_addpart(mime); - - m_returnCode = ""; - - curl_mime_data(part, reinterpret_cast(&zipData[0]), zipData.size()); - curl_mime_filename(part, std::string(fileName + ".zip").c_str()); - curl_mime_name(part, "file"); - - struct curl_slist * headers = NULL; - headers = curl_slist_append(headers, "Cache-Control: no-cache"); - - curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime); - curl_easy_setopt(m_curl, CURLOPT_URL, "https://anonfile.com/api/upload/"); - curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, "POST"); - curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writefunc); - curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &returnData); - curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, &xferinfo); - curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L); - - - if (curl_easy_perform(m_curl) != CURLE_OK) { - returnData = ""; - } - - std::string anonFileAddress; - - try { - json anonFileJson = json::parse(returnData); - - anonFileAddress = anonFileJson["data"]["file"]["url"]["short"]; - } catch(json::parse_error &e) { - printf("Parse error: %s\n", returnData.c_str()); - } - - if (anonFileAddress.find("https://anonfile.com/") != std::string::npos) { - std::stringstream ss; - ss << "http://werwolv.net/edizon_upload/sharedlink.php"; - ss << "?link=" << curl_easy_escape(m_curl, anonFileAddress.c_str(), anonFileAddress.length()); - ss << "&hash=" << hash; - ss << "&backupname=" << curl_easy_escape(m_curl, fileName.c_str(), fileName.length()); - ss << "&gamename=" << curl_easy_escape(m_curl, title->getTitleName().c_str(), title->getTitleName().length()); - ss << "&titleid=" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << title->getTitleID(); - - - struct curl_slist * headers = NULL; - headers = curl_slist_append(headers, "Cache-Control: no-cache"); - - curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(m_curl, CURLOPT_URL, ss.str().c_str()); - curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writefunc); - curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_returnCode); - - CURLcode res = curl_easy_perform(m_curl); - if (res != CURLE_OK) - printf("Error %d\n", res); - } - - curl_mime_free(mime); - - return m_returnCode; -} - -bool UploadManager::zip(std::vector paths, std::vector *zipData) { - zipper::Zipper archive(*zipData); - - u8 pathOffset = 25; - u32 currFile = 0; - - if (paths[0].find(EDIZON_DIR "/batch/") != std::string::npos) - pathOffset = 14; - else if (paths[0].find(EDIZON_DIR "/restore/") != std::string::npos) - pathOffset = 16; - - for(auto path : paths) { - std::ifstream file = std::ifstream(path); - - archive.add(file, &path.c_str()[pathOffset], zipper::Zipper::Better); - - if (Gui::g_currMessageBox != nullptr) - Gui::g_currMessageBox->setProgress(((++currFile / static_cast(paths.size())) * 100) / 2.0F); - - hidScanInput(); - if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B) - return false; - - file.close(); - } - - archive.close(); - - return true; +#include "upload_manager.hpp" + +#include "zipper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "guis/gui.hpp" +#include "json.hpp" + +using json = nlohmann::json; + +UploadManager::UploadManager() { + m_curl = curl_easy_init(); + + if (!m_curl) + printf("Curl initialization failed!\n"); +} + +UploadManager::~UploadManager() { + curl_easy_cleanup(m_curl); +} + +size_t writefunc(void *ptr, size_t size, size_t nmemb, std::string* s) { + *s += reinterpret_cast(ptr); + return size*nmemb; +} + +std::vector listFiles(const std::string &path) { + std::vector paths; + if (auto dir = opendir(path.c_str())) { + while (auto f = readdir(dir)) { + if (!f->d_name || f->d_name[0] == '.') continue; + if (f->d_type == DT_DIR) + listFiles(path + f->d_name + "/"); + + if (f->d_type == DT_REG) + paths.push_back(path + "/" + f->d_name); + } + closedir(dir); + } + + return paths; +} + +static int xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->setProgress(50.0F + ((ulnow / static_cast(ultotal)) * 100) / 2.0F); + + hidScanInput(); + + return hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B; +} + +std::string UploadManager::upload(std::string path, std::string fileName, Title *title, std::string hash) { + if (gethostid() == INADDR_LOOPBACK) return ""; + + std::vector zipData; + std::string returnData; + + std::vector filePaths; + std::filesystem::recursive_directory_iterator end; + for (std::filesystem::recursive_directory_iterator it(path); it != end; ++it) + if (!it->is_directory()) + filePaths.push_back(it->path().c_str()); + + if (!this->zip(filePaths, &zipData)) return ""; + + curl_mime *mime; + curl_mimepart *part; + + mime = curl_mime_init(m_curl); + part = curl_mime_addpart(mime); + + m_returnCode = ""; + + curl_mime_data(part, reinterpret_cast(&zipData[0]), zipData.size()); + curl_mime_filename(part, std::string(fileName + ".zip").c_str()); + curl_mime_name(part, "file"); + + struct curl_slist * headers = NULL; + headers = curl_slist_append(headers, "Cache-Control: no-cache"); + + curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime); + curl_easy_setopt(m_curl, CURLOPT_URL, "https://anonfile.com/api/upload/"); + curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, "POST"); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writefunc); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &returnData); + curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, &xferinfo); + curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L); + + + if (curl_easy_perform(m_curl) != CURLE_OK) { + returnData = ""; + } + + std::string anonFileAddress; + + try { + json anonFileJson = json::parse(returnData); + + anonFileAddress = anonFileJson["data"]["file"]["url"]["short"]; + } catch(json::parse_error &e) { + printf("Parse error: %s\n", returnData.c_str()); + } + + if (anonFileAddress.find("https://anonfile.com/") != std::string::npos) { + std::stringstream ss; + ss << "http://werwolv.net/edizon_upload/sharedlink.php"; + ss << "?link=" << curl_easy_escape(m_curl, anonFileAddress.c_str(), anonFileAddress.length()); + ss << "&hash=" << hash; + ss << "&backupname=" << curl_easy_escape(m_curl, fileName.c_str(), fileName.length()); + ss << "&gamename=" << curl_easy_escape(m_curl, title->getTitleName().c_str(), title->getTitleName().length()); + ss << "&titleid=" << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << title->getTitleID(); + + + struct curl_slist * headers = NULL; + headers = curl_slist_append(headers, "Cache-Control: no-cache"); + + curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(m_curl, CURLOPT_URL, ss.str().c_str()); + curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writefunc); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_returnCode); + + CURLcode res = curl_easy_perform(m_curl); + if (res != CURLE_OK) + printf("Error %d\n", res); + } + + curl_mime_free(mime); + + return m_returnCode; +} + +bool UploadManager::zip(std::vector paths, std::vector *zipData) { + zipper::Zipper archive(*zipData); + + u8 pathOffset = 25; + u32 currFile = 0; + + if (paths[0].find(EDIZON_DIR "/batch/") != std::string::npos) + pathOffset = 14; + else if (paths[0].find(EDIZON_DIR "/restore/") != std::string::npos) + pathOffset = 16; + + for(auto path : paths) { + std::ifstream file = std::ifstream(path); + + archive.add(file, &path.c_str()[pathOffset], zipper::Zipper::Better); + + if (Gui::g_currMessageBox != nullptr) + Gui::g_currMessageBox->setProgress(((++currFile / static_cast(paths.size())) * 100) / 2.0F); + + hidScanInput(); + if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B) + return false; + + file.close(); + } + + archive.close(); + + return true; } \ No newline at end of file diff --git a/source/widgets/widget.cpp b/source/widgets/widget.cpp index a3785818..c0820b31 100644 --- a/source/widgets/widget.cpp +++ b/source/widgets/widget.cpp @@ -1,166 +1,166 @@ -#include "widgets/widget.hpp" - -#include "guis/gui_editor.hpp" - -#include - -static s32 tooltipCnt = 0; - -Widget::Widget(Interpreter *interpreter, bool isDummy, std::string tooltip) : m_interpreter(interpreter), m_isDummy(isDummy), m_tooltip(tooltip) { - Widget::g_stepSizeMultiplier = 1; -} - -Widget::~Widget() { - Widget::g_stepSizeMultiplier = 1; -} - -void Widget::drawWidgets(Gui *gui, WidgetItems &widgets, u16 start, u16 end) { - static u16 oldWidgetIndex = 0; - - if (Widget::g_categories.empty() || widgets.empty()) return; - if (widgets.find(Widget::g_selectedCategory) == widgets.end()) return; - - ptrdiff_t categoryIndex = std::find(Widget::g_categories.begin(), Widget::g_categories.end(), Widget::g_selectedCategory) - Widget::g_categories.begin() - g_categoryYOffset; - if (Widget::g_selectedRow == CATEGORIES) { - gui->drawRectangled(25, 150 + 4 + 60 * categoryIndex, 310, 55, currTheme.highlightColor); - gui->drawRectangle(30, 150 + 9 + 60 * categoryIndex, 300, 45, currTheme.selectedButtonColor); - gui->drawShadow(25, 150 + 4 + 60 * categoryIndex, 310, 55); - } - - gui->drawRectangle(37, 150 + 13 + 60 * categoryIndex, 4, 35, currTheme.selectedColor); - - for (u8 i = 0; i < Widget::g_categories.size(); i++) { - gui->drawText(font20, 50, 150 + 15 + 60 * (i - g_categoryYOffset), Widget::g_categories[i] == Widget::g_selectedCategory ? currTheme.selectedColor : currTheme.textColor, Widget::g_categories[i].c_str()); - } - - std::vector &currWidgets = widgets[Widget::g_selectedCategory]; - - if (currWidgets.size() <= 0) return; - - u16 widgetInset = (Gui::g_framebuffer_width - WIDGET_WIDTH) / 2.0F; - u16 widgetY = 150; - - for (;start < end; start++) { - if (start > currWidgets.size() - 1) break; - - if (start == Widget::g_selectedWidgetIndex && Widget::g_selectedRow == WIDGETS) { - gui->drawRectangled(widgetInset + X_OFFSET, widgetY, WIDGET_WIDTH - 1, WIDGET_HEIGHT, currTheme.highlightColor); - gui->drawRectangle(widgetInset + 5 + X_OFFSET, widgetY + 5, WIDGET_WIDTH - 12, WIDGET_HEIGHT - 10, currTheme.selectedButtonColor); - gui->drawShadow(widgetInset + X_OFFSET, widgetY, WIDGET_WIDTH, WIDGET_HEIGHT); - } - - gui->drawTextAligned(font20, widgetInset + 50 + X_OFFSET, widgetY + (WIDGET_HEIGHT / 2.0F) - 13, currTheme.textColor, currWidgets[start].title.c_str(), ALIGNED_LEFT); - gui->drawRectangle(widgetInset + 30 + X_OFFSET, widgetY + WIDGET_HEIGHT + (WIDGET_SEPARATOR / 2) - 1, WIDGET_WIDTH - 60, 1, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); - currWidgets[start].widget->draw(gui, widgetInset + 50 + X_OFFSET, widgetY - 13); - - widgetY += WIDGET_HEIGHT + WIDGET_SEPARATOR; - } - - if (Widget::g_selectedRow == WIDGETS) { - if (Widget::g_selectedWidgetIndex != oldWidgetIndex) - tooltipCnt = 0; - else if (tooltipCnt < (8 * 60 + 0xFF)) - tooltipCnt = std::min(tooltipCnt + 16, 8 * 60 + 0xFF); - - if (currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip != "") { - if (Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE) > 3) - gui->drawTooltip(widgetInset + X_OFFSET + 200, 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * (Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE)), currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip.c_str(), currTheme.tooltipColor, currTheme.textColor, std::max(0, tooltipCnt - 8 * 60), true); - else - gui->drawTooltip(widgetInset + X_OFFSET + 200, 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * ((Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE)) + 1), currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip.c_str(), currTheme.tooltipColor, currTheme.textColor, std::max(0, tooltipCnt - 8 * 60), false); - } - } else tooltipCnt = 0; - - oldWidgetIndex = Widget::g_selectedWidgetIndex; - -} - -void Widget::handleInput(u32 kdown, WidgetItems &widgets) { - std::vector &currWidgets = widgets[Widget::g_selectedCategory]; - - if (currWidgets.size() > 0 && Widget::g_selectedRow == WIDGETS) - currWidgets[Widget::g_selectedWidgetIndex].widget->onInput(kdown); - - if (Widget::g_selectedRow == CATEGORIES) { - if (kdown & KEY_A || kdown & KEY_LSTICK_RIGHT || kdown & KEY_RSTICK_RIGHT) { - Widget::g_selectedRow = WIDGETS; - Widget::g_selectedWidgetIndex = Widget::g_widgetPage * WIDGETS_PER_PAGE; - } - } - - if (kdown & KEY_RSTICK) { - if (g_stepSizeMultiplier == 10000) g_stepSizeMultiplier = 1; - else g_stepSizeMultiplier *= 10; - } -} - -void Widget::handleTouch(touchPosition &touch, WidgetItems &widgets) { - std::vector &currWidgets = widgets[Widget::g_selectedCategory]; - - u16 widgetInset = (Gui::g_framebuffer_width - WIDGET_WIDTH) / 2.0F; - - if (touch.px > 30 && touch.px < 330) { /* Touch of categories area */ - u8 categoryIndex = std::floor((touch.py - 159) / 60.0F) + g_categoryYOffset; - - Widget::g_selectedRow = CATEGORIES; - - if (Widget::g_selectedCategory == Widget::g_categories[categoryIndex]) - Widget::g_selectedRow = WIDGETS; - else if (categoryIndex < Widget::g_categories.size()) { - Widget::g_selectedCategory = Widget::g_categories[categoryIndex]; - Widget::g_selectedWidgetIndex = categoryIndex; - } - - if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 7 && Widget::g_categoryYOffset != 0) - Widget::g_categoryYOffset--; - - if (Widget::g_selectedWidgetIndex > 6 && Widget::g_categoryYOffset < Widget::g_categories.size() - 8) - Widget::g_categoryYOffset++; - - } else if (touch.px > widgetInset + X_OFFSET && touch.px < widgetInset + X_OFFSET + WIDGET_WIDTH - && touch.py > 150 && touch.py < 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * WIDGETS_PER_PAGE) { /* Touch of widgets area */ - u16 widgetIndex = std::min(static_cast((touch.py - 150) / (WIDGET_HEIGHT + WIDGET_SEPARATOR) + Widget::g_widgetPage * WIDGETS_PER_PAGE), static_cast(currWidgets.size())); - - Widget::g_selectedRow = WIDGETS; - - if (Widget::g_selectedWidgetIndex != widgetIndex) - Widget::g_selectedWidgetIndex = widgetIndex; - else currWidgets[widgetIndex].widget->onTouch(touch); - } -} - -s64 Widget::getIntegerValue() { - m_interpreter->setArgs(m_intArgs, m_strArgs); - - return m_isDummy ? m_interpreter->getDummyValue() : m_interpreter->getValueFromSaveFile(); -} - -std::string Widget::getStringValue() { - m_interpreter->setArgs(m_intArgs, m_strArgs); - - return m_isDummy ? m_interpreter->getDummyString() : m_interpreter->getStringFromSaveFile(); -} - -void Widget::setIntegerValue(s64 value) { - m_interpreter->setArgs(m_intArgs, m_strArgs); - - if (Widget::isDummy()) - m_interpreter->setDummyValue(value); - else m_interpreter->setValueInSaveFile(value); -} - -void Widget::setStringValue(std::string value) { - m_interpreter->setArgs(m_intArgs, m_strArgs); - - if (Widget::isDummy()) - m_interpreter->setDummyString(value); - else m_interpreter->setStringInSaveFile(value); -} - -void Widget::setLuaArgs(std::vector intArgs, std::vector strArgs) { - this->m_intArgs = intArgs; - this->m_strArgs = strArgs; -} - -bool Widget::isDummy() { - return this->m_isDummy; -} +#include "widgets/widget.hpp" + +#include "guis/gui_editor.hpp" + +#include + +static s32 tooltipCnt = 0; + +Widget::Widget(Interpreter *interpreter, bool isDummy, std::string tooltip) : m_interpreter(interpreter), m_isDummy(isDummy), m_tooltip(tooltip) { + Widget::g_stepSizeMultiplier = 1; +} + +Widget::~Widget() { + Widget::g_stepSizeMultiplier = 1; +} + +void Widget::drawWidgets(Gui *gui, WidgetItems &widgets, u16 start, u16 end) { + static u16 oldWidgetIndex = 0; + + if (Widget::g_categories.empty() || widgets.empty()) return; + if (widgets.find(Widget::g_selectedCategory) == widgets.end()) return; + + ptrdiff_t categoryIndex = std::find(Widget::g_categories.begin(), Widget::g_categories.end(), Widget::g_selectedCategory) - Widget::g_categories.begin() - g_categoryYOffset; + if (Widget::g_selectedRow == CATEGORIES) { + gui->drawRectangled(25, 150 + 4 + 60 * categoryIndex, 310, 55, currTheme.highlightColor); + gui->drawRectangle(30, 150 + 9 + 60 * categoryIndex, 300, 45, currTheme.selectedButtonColor); + gui->drawShadow(25, 150 + 4 + 60 * categoryIndex, 310, 55); + } + + gui->drawRectangle(37, 150 + 13 + 60 * categoryIndex, 4, 35, currTheme.selectedColor); + + for (u8 i = 0; i < Widget::g_categories.size(); i++) { + gui->drawText(font20, 50, 150 + 15 + 60 * (i - g_categoryYOffset), Widget::g_categories[i] == Widget::g_selectedCategory ? currTheme.selectedColor : currTheme.textColor, Widget::g_categories[i].c_str()); + } + + std::vector &currWidgets = widgets[Widget::g_selectedCategory]; + + if (currWidgets.size() <= 0) return; + + u16 widgetInset = (Gui::g_framebuffer_width - WIDGET_WIDTH) / 2.0F; + u16 widgetY = 150; + + for (;start < end; start++) { + if (start > currWidgets.size() - 1) break; + + if (start == Widget::g_selectedWidgetIndex && Widget::g_selectedRow == WIDGETS) { + gui->drawRectangled(widgetInset + X_OFFSET, widgetY, WIDGET_WIDTH - 1, WIDGET_HEIGHT, currTheme.highlightColor); + gui->drawRectangle(widgetInset + 5 + X_OFFSET, widgetY + 5, WIDGET_WIDTH - 12, WIDGET_HEIGHT - 10, currTheme.selectedButtonColor); + gui->drawShadow(widgetInset + X_OFFSET, widgetY, WIDGET_WIDTH, WIDGET_HEIGHT); + } + + gui->drawTextAligned(font20, widgetInset + 50 + X_OFFSET, widgetY + (WIDGET_HEIGHT / 2.0F) - 13, currTheme.textColor, currWidgets[start].title.c_str(), ALIGNED_LEFT); + gui->drawRectangle(widgetInset + 30 + X_OFFSET, widgetY + WIDGET_HEIGHT + (WIDGET_SEPARATOR / 2) - 1, WIDGET_WIDTH - 60, 1, gui->makeColor(0x00, 0x00, 0x00, 0xFF)); + currWidgets[start].widget->draw(gui, widgetInset + 50 + X_OFFSET, widgetY - 13); + + widgetY += WIDGET_HEIGHT + WIDGET_SEPARATOR; + } + + if (Widget::g_selectedRow == WIDGETS) { + if (Widget::g_selectedWidgetIndex != oldWidgetIndex) + tooltipCnt = 0; + else if (tooltipCnt < (8 * 60 + 0xFF)) + tooltipCnt = std::min(tooltipCnt + 16, 8 * 60 + 0xFF); + + if (currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip != "") { + if (Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE) > 3) + gui->drawTooltip(widgetInset + X_OFFSET + 200, 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * (Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE)), currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip.c_str(), currTheme.tooltipColor, currTheme.textColor, std::max(0, tooltipCnt - 8 * 60), true); + else + gui->drawTooltip(widgetInset + X_OFFSET + 200, 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * ((Widget::g_selectedWidgetIndex % static_cast(WIDGETS_PER_PAGE)) + 1), currWidgets[Widget::g_selectedWidgetIndex].widget->m_tooltip.c_str(), currTheme.tooltipColor, currTheme.textColor, std::max(0, tooltipCnt - 8 * 60), false); + } + } else tooltipCnt = 0; + + oldWidgetIndex = Widget::g_selectedWidgetIndex; + +} + +void Widget::handleInput(u32 kdown, WidgetItems &widgets) { + std::vector &currWidgets = widgets[Widget::g_selectedCategory]; + + if (currWidgets.size() > 0 && Widget::g_selectedRow == WIDGETS) + currWidgets[Widget::g_selectedWidgetIndex].widget->onInput(kdown); + + if (Widget::g_selectedRow == CATEGORIES) { + if (kdown & KEY_A || kdown & KEY_LSTICK_RIGHT || kdown & KEY_RSTICK_RIGHT) { + Widget::g_selectedRow = WIDGETS; + Widget::g_selectedWidgetIndex = Widget::g_widgetPage * WIDGETS_PER_PAGE; + } + } + + if (kdown & KEY_RSTICK) { + if (g_stepSizeMultiplier == 10000) g_stepSizeMultiplier = 1; + else g_stepSizeMultiplier *= 10; + } +} + +void Widget::handleTouch(touchPosition &touch, WidgetItems &widgets) { + std::vector &currWidgets = widgets[Widget::g_selectedCategory]; + + u16 widgetInset = (Gui::g_framebuffer_width - WIDGET_WIDTH) / 2.0F; + + if (touch.px > 30 && touch.px < 330) { /* Touch of categories area */ + u8 categoryIndex = std::floor((touch.py - 159) / 60.0F) + g_categoryYOffset; + + Widget::g_selectedRow = CATEGORIES; + + if (Widget::g_selectedCategory == Widget::g_categories[categoryIndex]) + Widget::g_selectedRow = WIDGETS; + else if (categoryIndex < Widget::g_categories.size()) { + Widget::g_selectedCategory = Widget::g_categories[categoryIndex]; + Widget::g_selectedWidgetIndex = categoryIndex; + } + + if (Widget::g_selectedWidgetIndex < Widget::g_categories.size() - 7 && Widget::g_categoryYOffset != 0) + Widget::g_categoryYOffset--; + + if (Widget::g_selectedWidgetIndex > 6 && Widget::g_categoryYOffset < Widget::g_categories.size() - 8) + Widget::g_categoryYOffset++; + + } else if (touch.px > widgetInset + X_OFFSET && touch.px < widgetInset + X_OFFSET + WIDGET_WIDTH + && touch.py > 150 && touch.py < 150 + (WIDGET_HEIGHT + WIDGET_SEPARATOR) * WIDGETS_PER_PAGE) { /* Touch of widgets area */ + u16 widgetIndex = std::min(static_cast((touch.py - 150) / (WIDGET_HEIGHT + WIDGET_SEPARATOR) + Widget::g_widgetPage * WIDGETS_PER_PAGE), static_cast(currWidgets.size())); + + Widget::g_selectedRow = WIDGETS; + + if (Widget::g_selectedWidgetIndex != widgetIndex) + Widget::g_selectedWidgetIndex = widgetIndex; + else currWidgets[widgetIndex].widget->onTouch(touch); + } +} + +s64 Widget::getIntegerValue() { + m_interpreter->setArgs(m_intArgs, m_strArgs); + + return m_isDummy ? m_interpreter->getDummyValue() : m_interpreter->getValueFromSaveFile(); +} + +std::string Widget::getStringValue() { + m_interpreter->setArgs(m_intArgs, m_strArgs); + + return m_isDummy ? m_interpreter->getDummyString() : m_interpreter->getStringFromSaveFile(); +} + +void Widget::setIntegerValue(s64 value) { + m_interpreter->setArgs(m_intArgs, m_strArgs); + + if (Widget::isDummy()) + m_interpreter->setDummyValue(value); + else m_interpreter->setValueInSaveFile(value); +} + +void Widget::setStringValue(std::string value) { + m_interpreter->setArgs(m_intArgs, m_strArgs); + + if (Widget::isDummy()) + m_interpreter->setDummyString(value); + else m_interpreter->setStringInSaveFile(value); +} + +void Widget::setLuaArgs(std::vector intArgs, std::vector strArgs) { + this->m_intArgs = intArgs; + this->m_strArgs = strArgs; +} + +bool Widget::isDummy() { + return this->m_isDummy; +} diff --git a/source/widgets/widget_button.cpp b/source/widgets/widget_button.cpp index 22c3a358..c5f5e6b6 100644 --- a/source/widgets/widget_button.cpp +++ b/source/widgets/widget_button.cpp @@ -1,37 +1,37 @@ -#include "widgets/widget_button.hpp" - -WidgetButton::WidgetButton(Interpreter *interpreter, std::string tooltip, std::string funcName) : - Widget(interpreter, false, tooltip), m_funcName(funcName) { - m_widgetDataType = STRING; - - m_displayText = ""; -} - -WidgetButton::~WidgetButton() { - -} - -void WidgetButton::draw(Gui *gui, u16 x, u16 y) { - std::string displayText = m_displayText; - - std::replace(displayText.begin(), displayText.end(), '\n', ' '); - - if(displayText.length() >= 25) { - displayText = displayText.substr(0, 24); - displayText += "..."; - } - - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), gui->makeColor(0x00, 0x00, 0x00, 0xFF), displayText.c_str(), ALIGNED_RIGHT); -} - -void WidgetButton::onInput(u32 kdown) { - if (kdown & KEY_A) { - m_interpreter->setArgs(m_intArgs, m_strArgs); - m_displayText = m_interpreter->callFunction(m_funcName); - } -} - -void WidgetButton::onTouch(touchPosition &touch) { - m_interpreter->setArgs(m_intArgs, m_strArgs); - m_displayText = m_interpreter->callFunction(m_funcName); -} +#include "widgets/widget_button.hpp" + +WidgetButton::WidgetButton(Interpreter *interpreter, std::string tooltip, std::string funcName) : + Widget(interpreter, false, tooltip), m_funcName(funcName) { + m_widgetDataType = STRING; + + m_displayText = ""; +} + +WidgetButton::~WidgetButton() { + +} + +void WidgetButton::draw(Gui *gui, u16 x, u16 y) { + std::string displayText = m_displayText; + + std::replace(displayText.begin(), displayText.end(), '\n', ' '); + + if(displayText.length() >= 25) { + displayText = displayText.substr(0, 24); + displayText += "..."; + } + + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), gui->makeColor(0x00, 0x00, 0x00, 0xFF), displayText.c_str(), ALIGNED_RIGHT); +} + +void WidgetButton::onInput(u32 kdown) { + if (kdown & KEY_A) { + m_interpreter->setArgs(m_intArgs, m_strArgs); + m_displayText = m_interpreter->callFunction(m_funcName); + } +} + +void WidgetButton::onTouch(touchPosition &touch) { + m_interpreter->setArgs(m_intArgs, m_strArgs); + m_displayText = m_interpreter->callFunction(m_funcName); +} diff --git a/source/widgets/widget_comment.cpp b/source/widgets/widget_comment.cpp index 155beeff..578eee81 100644 --- a/source/widgets/widget_comment.cpp +++ b/source/widgets/widget_comment.cpp @@ -1,32 +1,32 @@ -#include "widgets/widget_comment.hpp" - -WidgetComment::WidgetComment(Interpreter *interpreter, std::string tooltip, std::string text) : - Widget(interpreter, true, tooltip), m_text(text) { - m_widgetDataType = STRING; -} - -WidgetComment::~WidgetComment() { - -} - -void WidgetComment::draw(Gui *gui, u16 x, u16 y) { - std::string displayString = m_text; - - std::replace(displayString.begin(), displayString.end(), '\n', ' '); - - if(displayString.length() >= 25) { - displayString = displayString.substr(0, 24); - displayString += "..."; - } - - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), gui->makeColor(0x00, 0x00, 0x00, 0xFF), displayString.c_str(), ALIGNED_RIGHT); -} - -void WidgetComment::onInput(u32 kdown) { - if (kdown & KEY_A) - (new MessageBox(m_text, MessageBox::OKAY))->show(); -} - -void WidgetComment::onTouch(touchPosition &touch) { - (new MessageBox(m_text, MessageBox::OKAY))->show(); -} +#include "widgets/widget_comment.hpp" + +WidgetComment::WidgetComment(Interpreter *interpreter, std::string tooltip, std::string text) : + Widget(interpreter, true, tooltip), m_text(text) { + m_widgetDataType = STRING; +} + +WidgetComment::~WidgetComment() { + +} + +void WidgetComment::draw(Gui *gui, u16 x, u16 y) { + std::string displayString = m_text; + + std::replace(displayString.begin(), displayString.end(), '\n', ' '); + + if(displayString.length() >= 25) { + displayString = displayString.substr(0, 24); + displayString += "..."; + } + + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), gui->makeColor(0x00, 0x00, 0x00, 0xFF), displayString.c_str(), ALIGNED_RIGHT); +} + +void WidgetComment::onInput(u32 kdown) { + if (kdown & KEY_A) + (new MessageBox(m_text, MessageBox::OKAY))->show(); +} + +void WidgetComment::onTouch(touchPosition &touch) { + (new MessageBox(m_text, MessageBox::OKAY))->show(); +} diff --git a/source/widgets/widget_list.cpp b/source/widgets/widget_list.cpp index 96bfe3fe..86f4a28c 100644 --- a/source/widgets/widget_list.cpp +++ b/source/widgets/widget_list.cpp @@ -1,66 +1,66 @@ -#include "widgets/widget_list.hpp" - -#include "ui_elements/list_selector.hpp" - -WidgetList::WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues) : - Widget(interpreter, isDummy, tooltip), m_listItemNames(listItemNames), m_intListItemValues(listItemValues) { - m_widgetDataType = INT; -} - -WidgetList::WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues) : - Widget(interpreter, isDummy, tooltip), m_listItemNames(listItemNames), m_strListItemValues(listItemValues) { - m_widgetDataType = STRING; -} - -WidgetList::~WidgetList() { - -} - -void WidgetList::draw(Gui *gui, u16 x, u16 y) { - std::stringstream ss; - if (m_widgetDataType == INT) { - s64 intValue = Widget::getIntegerValue(); - if (std::find(m_intListItemValues.begin(), m_intListItemValues.end(), intValue) != m_intListItemValues.end()) { - ptrdiff_t pos = find(m_intListItemValues.begin(), m_intListItemValues.end(), intValue) - m_intListItemValues.begin(); - ss << m_listItemNames[pos]; - } else { - ss << "Unknown value: " << intValue; - } - } else if (m_widgetDataType == STRING) { - std::string strValue = Widget::getStringValue(); - if (std::find(m_strListItemValues.begin(), m_strListItemValues.end(), strValue) != m_strListItemValues.end()) { - ptrdiff_t pos = find(m_strListItemValues.begin(), m_strListItemValues.end(), strValue) - m_strListItemValues.begin(); - ss << m_listItemNames[pos]; - } else { - ss << "Unknown value: " << strValue; - } - } - - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, ss.str().c_str(), ALIGNED_RIGHT); -} - -void WidgetList::onInput(u32 kdown) { - if (kdown & KEY_A && Gui::g_currListSelector == nullptr) { - (new ListSelector("Choose item", "\uE0E0 - Select \uE0E1 - Back", m_listItemNames))->setInputAction([&](u32 k, u16 selectedItem){ - if(k & KEY_A) { - if (m_widgetDataType == INT) - Widget::setIntegerValue(m_intListItemValues[selectedItem]); - else if (m_widgetDataType == STRING) - Widget::setStringValue(m_strListItemValues[selectedItem]); - Gui::g_currListSelector->hide(); - } - })->show(); - } -} - -void WidgetList::onTouch(touchPosition &touch) { - (new ListSelector("Choose item", "\uE0E0 - Select \uE0E1 - Back", m_listItemNames))->setInputAction([&](u32 k, u16 selectedItem){ - if(k & KEY_A) { - if (m_widgetDataType == INT) - Widget::setIntegerValue(m_intListItemValues[selectedItem]); - else if (m_widgetDataType == STRING) - Widget::setStringValue(m_strListItemValues[selectedItem]); - Gui::g_currListSelector->hide(); - } - })->show(); -} +#include "widgets/widget_list.hpp" + +#include "ui_elements/list_selector.hpp" + +WidgetList::WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues) : + Widget(interpreter, isDummy, tooltip), m_listItemNames(listItemNames), m_intListItemValues(listItemValues) { + m_widgetDataType = INT; +} + +WidgetList::WidgetList(Interpreter *interpreter, bool isDummy, std::string tooltip, std::vector listItemNames, std::vector listItemValues) : + Widget(interpreter, isDummy, tooltip), m_listItemNames(listItemNames), m_strListItemValues(listItemValues) { + m_widgetDataType = STRING; +} + +WidgetList::~WidgetList() { + +} + +void WidgetList::draw(Gui *gui, u16 x, u16 y) { + std::stringstream ss; + if (m_widgetDataType == INT) { + s64 intValue = Widget::getIntegerValue(); + if (std::find(m_intListItemValues.begin(), m_intListItemValues.end(), intValue) != m_intListItemValues.end()) { + ptrdiff_t pos = find(m_intListItemValues.begin(), m_intListItemValues.end(), intValue) - m_intListItemValues.begin(); + ss << m_listItemNames[pos]; + } else { + ss << "Unknown value: " << intValue; + } + } else if (m_widgetDataType == STRING) { + std::string strValue = Widget::getStringValue(); + if (std::find(m_strListItemValues.begin(), m_strListItemValues.end(), strValue) != m_strListItemValues.end()) { + ptrdiff_t pos = find(m_strListItemValues.begin(), m_strListItemValues.end(), strValue) - m_strListItemValues.begin(); + ss << m_listItemNames[pos]; + } else { + ss << "Unknown value: " << strValue; + } + } + + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, ss.str().c_str(), ALIGNED_RIGHT); +} + +void WidgetList::onInput(u32 kdown) { + if (kdown & KEY_A && Gui::g_currListSelector == nullptr) { + (new ListSelector("Choose item", "\uE0E0 - Select \uE0E1 - Back", m_listItemNames))->setInputAction([&](u32 k, u16 selectedItem){ + if(k & KEY_A) { + if (m_widgetDataType == INT) + Widget::setIntegerValue(m_intListItemValues[selectedItem]); + else if (m_widgetDataType == STRING) + Widget::setStringValue(m_strListItemValues[selectedItem]); + Gui::g_currListSelector->hide(); + } + })->show(); + } +} + +void WidgetList::onTouch(touchPosition &touch) { + (new ListSelector("Choose item", "\uE0E0 - Select \uE0E1 - Back", m_listItemNames))->setInputAction([&](u32 k, u16 selectedItem){ + if(k & KEY_A) { + if (m_widgetDataType == INT) + Widget::setIntegerValue(m_intListItemValues[selectedItem]); + else if (m_widgetDataType == STRING) + Widget::setStringValue(m_strListItemValues[selectedItem]); + Gui::g_currListSelector->hide(); + } + })->show(); +} diff --git a/source/widgets/widget_string.cpp b/source/widgets/widget_string.cpp index a74a9ab4..2641f22d 100644 --- a/source/widgets/widget_string.cpp +++ b/source/widgets/widget_string.cpp @@ -1,41 +1,41 @@ -#include "widgets/widget_string.hpp" - -WidgetString::WidgetString(Interpreter *interpreter, bool isDummy, std::string tooltip, u8 minLength, u8 maxLength) : - Widget(interpreter, isDummy, tooltip), m_minLength(minLength), m_maxLength(maxLength) { - m_widgetDataType = STRING; -} - -WidgetString::~WidgetString() { - -} - -void WidgetString::draw(Gui *gui, u16 x, u16 y) { - std::string displayString = Widget::getStringValue(); - - if(displayString.length() >= 15) { - displayString = displayString.substr(0, 14); - displayString += "..."; - } - - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, displayString.c_str(), ALIGNED_RIGHT); -} - -void WidgetString::onInput(u32 kdown) { - if (kdown & KEY_A) { - char out_string[m_maxLength + 1]; - Gui::requestKeyboardInput("Input string value", "Enter a string for this value to be set to.", Widget::getStringValue(), SwkbdType_Normal, out_string, m_maxLength); - - if (std::strlen(out_string) > m_minLength) - Widget::setStringValue(out_string); - else (new Snackbar("Input string has to be longer than " + std::to_string(m_minLength) + " characters!"))->show(); - } -} - -void WidgetString::onTouch(touchPosition &touch) { - char out_string[m_maxLength + 1]; - Gui::requestKeyboardInput("Input string value", "Enter a string for this value to be set to.", Widget::getStringValue(), SwkbdType_Normal, out_string, m_maxLength); - - if (std::strlen(out_string) > m_minLength) - Widget::setStringValue(out_string); - else (new Snackbar("Input string has to be longer than " + std::to_string(m_minLength) + " characters!"))->show(); -} +#include "widgets/widget_string.hpp" + +WidgetString::WidgetString(Interpreter *interpreter, bool isDummy, std::string tooltip, u8 minLength, u8 maxLength) : + Widget(interpreter, isDummy, tooltip), m_minLength(minLength), m_maxLength(maxLength) { + m_widgetDataType = STRING; +} + +WidgetString::~WidgetString() { + +} + +void WidgetString::draw(Gui *gui, u16 x, u16 y) { + std::string displayString = Widget::getStringValue(); + + if(displayString.length() >= 15) { + displayString = displayString.substr(0, 14); + displayString += "..."; + } + + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, displayString.c_str(), ALIGNED_RIGHT); +} + +void WidgetString::onInput(u32 kdown) { + if (kdown & KEY_A) { + char out_string[m_maxLength + 1]; + Gui::requestKeyboardInput("Input string value", "Enter a string for this value to be set to.", Widget::getStringValue(), SwkbdType_Normal, out_string, m_maxLength); + + if (std::strlen(out_string) > m_minLength) + Widget::setStringValue(out_string); + else (new Snackbar("Input string has to be longer than " + std::to_string(m_minLength) + " characters!"))->show(); + } +} + +void WidgetString::onTouch(touchPosition &touch) { + char out_string[m_maxLength + 1]; + Gui::requestKeyboardInput("Input string value", "Enter a string for this value to be set to.", Widget::getStringValue(), SwkbdType_Normal, out_string, m_maxLength); + + if (std::strlen(out_string) > m_minLength) + Widget::setStringValue(out_string); + else (new Snackbar("Input string has to be longer than " + std::to_string(m_minLength) + " characters!"))->show(); +} diff --git a/source/widgets/widget_switch.cpp b/source/widgets/widget_switch.cpp index 5cd8cc27..41c12a31 100644 --- a/source/widgets/widget_switch.cpp +++ b/source/widgets/widget_switch.cpp @@ -1,57 +1,57 @@ -#include "widgets/widget_switch.hpp" - -WidgetSwitch::WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, s32 onValue, s32 offValue) : - Widget(interpreter, isDummy, tooltip), m_intOnValue(onValue), m_intOffValue(offValue) { - m_widgetDataType = INT; -} - -WidgetSwitch::WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string onValue, std::string offValue) : - Widget(interpreter, isDummy, tooltip), m_strOnValue(onValue), m_strOffValue(offValue){ - m_widgetDataType = STRING; -} - - -WidgetSwitch::~WidgetSwitch() { - -} - -void WidgetSwitch::draw(Gui *gui, u16 x, u16 y) { - if (m_widgetDataType == INT) { - s64 intValue = Widget::getIntegerValue(); - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), intValue == m_intOnValue ? currTheme.selectedColor : currTheme.separatorColor, intValue == m_intOnValue ? "ON" : "OFF", ALIGNED_RIGHT); - } - else if (m_widgetDataType == STRING) { - std::string strValue = Widget::getStringValue(); - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), strValue == m_strOnValue ? currTheme.selectedColor : currTheme.separatorColor, strValue == m_strOnValue ? "ON" : "OFF", ALIGNED_RIGHT); - } -} - -void WidgetSwitch::onInput(u32 kdown) { - if (kdown & KEY_A) { - if (m_widgetDataType == INT) { - if (Widget::getIntegerValue() == m_intOnValue) - Widget::setIntegerValue(m_intOffValue); - else - Widget::setIntegerValue(m_intOnValue); - } else if (m_widgetDataType == STRING) { - if (Widget::getStringValue() == m_strOnValue) - Widget::setStringValue(m_strOffValue); - else - Widget::setStringValue(m_strOnValue); - } - } -} - -void WidgetSwitch::onTouch(touchPosition &touch) { - if (m_widgetDataType == INT) { - if (Widget::getIntegerValue() == m_intOnValue) - Widget::setIntegerValue(m_intOffValue); - else - Widget::setIntegerValue(m_intOnValue); - } else if (m_widgetDataType == STRING) { - if (Widget::getStringValue() == m_strOnValue) - Widget::setStringValue(m_strOffValue); - else - Widget::setStringValue(m_strOnValue); - } -} +#include "widgets/widget_switch.hpp" + +WidgetSwitch::WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, s32 onValue, s32 offValue) : + Widget(interpreter, isDummy, tooltip), m_intOnValue(onValue), m_intOffValue(offValue) { + m_widgetDataType = INT; +} + +WidgetSwitch::WidgetSwitch(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string onValue, std::string offValue) : + Widget(interpreter, isDummy, tooltip), m_strOnValue(onValue), m_strOffValue(offValue){ + m_widgetDataType = STRING; +} + + +WidgetSwitch::~WidgetSwitch() { + +} + +void WidgetSwitch::draw(Gui *gui, u16 x, u16 y) { + if (m_widgetDataType == INT) { + s64 intValue = Widget::getIntegerValue(); + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), intValue == m_intOnValue ? currTheme.selectedColor : currTheme.separatorColor, intValue == m_intOnValue ? "ON" : "OFF", ALIGNED_RIGHT); + } + else if (m_widgetDataType == STRING) { + std::string strValue = Widget::getStringValue(); + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), strValue == m_strOnValue ? currTheme.selectedColor : currTheme.separatorColor, strValue == m_strOnValue ? "ON" : "OFF", ALIGNED_RIGHT); + } +} + +void WidgetSwitch::onInput(u32 kdown) { + if (kdown & KEY_A) { + if (m_widgetDataType == INT) { + if (Widget::getIntegerValue() == m_intOnValue) + Widget::setIntegerValue(m_intOffValue); + else + Widget::setIntegerValue(m_intOnValue); + } else if (m_widgetDataType == STRING) { + if (Widget::getStringValue() == m_strOnValue) + Widget::setStringValue(m_strOffValue); + else + Widget::setStringValue(m_strOnValue); + } + } +} + +void WidgetSwitch::onTouch(touchPosition &touch) { + if (m_widgetDataType == INT) { + if (Widget::getIntegerValue() == m_intOnValue) + Widget::setIntegerValue(m_intOffValue); + else + Widget::setIntegerValue(m_intOnValue); + } else if (m_widgetDataType == STRING) { + if (Widget::getStringValue() == m_strOnValue) + Widget::setStringValue(m_strOffValue); + else + Widget::setStringValue(m_strOnValue); + } +} diff --git a/source/widgets/widget_value.cpp b/source/widgets/widget_value.cpp index 920065ef..3c3bc27e 100644 --- a/source/widgets/widget_value.cpp +++ b/source/widgets/widget_value.cpp @@ -1,85 +1,85 @@ -#include "widgets/widget_value.hpp" - -#include - -#define ACCELERATION_DELAY 50 - -WidgetValue::WidgetValue(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string readEquation, std::string writeEquation, s64 minValue, s64 maxValue, u64 stepSize) : - Widget(interpreter, isDummy, tooltip), m_readEquation(readEquation), m_writeEquation(writeEquation), m_minValue(minValue), m_maxValue(maxValue), m_stepSize(stepSize) { - m_widgetDataType = INT; - - m_currValue = 0; - -} - -WidgetValue::~WidgetValue() { - -} - -void WidgetValue::draw(Gui *gui, u16 x, u16 y) { - std::stringstream ss; - ss << m_currValue; - - m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); - - gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, ss.str().c_str(), ALIGNED_RIGHT); -} - -bool isNumber(const std::string &line) { - if (line[0] == '0') return true; - return (atoi(line.c_str())); -} - -void WidgetValue::onInput(u32 kdown) { - u64 incrementValue = m_stepSize * g_stepSizeMultiplier; - - if (kdown & KEY_DLEFT) { - if (static_cast(m_currValue - incrementValue) >= m_minValue) - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_currValue) - incrementValue); - else if(m_currValue < m_minValue) - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_maxValue)); - else - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_minValue)); - } - - if (kdown & KEY_DRIGHT) { - if (static_cast(m_currValue + incrementValue) <= m_maxValue) - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_currValue) + incrementValue); - else if(m_currValue > m_maxValue) - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_minValue)); - else - Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_maxValue)); - } - - if (kdown & KEY_A) { - u8 maxDigits = static_cast(std::floor(std::log10(m_maxValue)) + 1); - - char out_number[maxDigits + 1]; - Gui::requestKeyboardInput("Input value", "Enter a number for this value to be set to.", std::to_string(m_currValue).c_str(), SwkbdType_NumPad, out_number, maxDigits); - - if (isNumber(std::string(out_number))) - Widget::setIntegerValue( - Widget::m_interpreter->evaluateEquation(m_writeEquation, - Widget::m_interpreter->evaluateEquation(m_readEquation, - std::min(std::max(static_cast(atoi(out_number)), - m_minValue), m_maxValue)))); - } - - m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); -} - -void WidgetValue::onTouch(touchPosition &touch) { - u8 maxDigits = static_cast(std::floor(std::log10(m_maxValue)) + 1); - - char out_number[maxDigits + 1]; - Gui::requestKeyboardInput("Input value", "Enter a number for this value to be set to.", std::to_string(m_currValue).c_str(), SwkbdType_NumPad, out_number, maxDigits); - - if (isNumber(std::string(out_number))) - Widget::setIntegerValue( - Widget::m_interpreter->evaluateEquation(m_writeEquation, - Widget::m_interpreter->evaluateEquation(m_readEquation, - std::min(std::max(static_cast(atoi(out_number)), - m_minValue), m_maxValue)))); - - m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); -} +#include "widgets/widget_value.hpp" + +#include + +#define ACCELERATION_DELAY 50 + +WidgetValue::WidgetValue(Interpreter *interpreter, bool isDummy, std::string tooltip, std::string readEquation, std::string writeEquation, s64 minValue, s64 maxValue, u64 stepSize) : + Widget(interpreter, isDummy, tooltip), m_readEquation(readEquation), m_writeEquation(writeEquation), m_minValue(minValue), m_maxValue(maxValue), m_stepSize(stepSize) { + m_widgetDataType = INT; + + m_currValue = 0; + +} + +WidgetValue::~WidgetValue() { + +} + +void WidgetValue::draw(Gui *gui, u16 x, u16 y) { + std::stringstream ss; + ss << m_currValue; + + m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); + + gui->drawTextAligned(font20, x + WIDGET_WIDTH - 140, y + (WIDGET_HEIGHT / 2.0F), currTheme.selectedColor, ss.str().c_str(), ALIGNED_RIGHT); +} + +bool isNumber(const std::string &line) { + if (line[0] == '0') return true; + return (atoi(line.c_str())); +} + +void WidgetValue::onInput(u32 kdown) { + u64 incrementValue = m_stepSize * g_stepSizeMultiplier; + + if (kdown & KEY_DLEFT) { + if (static_cast(m_currValue - incrementValue) >= m_minValue) + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_currValue) - incrementValue); + else if(m_currValue < m_minValue) + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_maxValue)); + else + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_minValue)); + } + + if (kdown & KEY_DRIGHT) { + if (static_cast(m_currValue + incrementValue) <= m_maxValue) + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_currValue) + incrementValue); + else if(m_currValue > m_maxValue) + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_minValue)); + else + Widget::setIntegerValue(Widget::m_interpreter->evaluateEquation(m_writeEquation, m_maxValue)); + } + + if (kdown & KEY_A) { + u8 maxDigits = static_cast(std::floor(std::log10(m_maxValue)) + 1); + + char out_number[maxDigits + 1]; + Gui::requestKeyboardInput("Input value", "Enter a number for this value to be set to.", std::to_string(m_currValue).c_str(), SwkbdType_NumPad, out_number, maxDigits); + + if (isNumber(std::string(out_number))) + Widget::setIntegerValue( + Widget::m_interpreter->evaluateEquation(m_writeEquation, + Widget::m_interpreter->evaluateEquation(m_readEquation, + std::min(std::max(static_cast(atoi(out_number)), + m_minValue), m_maxValue)))); + } + + m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); +} + +void WidgetValue::onTouch(touchPosition &touch) { + u8 maxDigits = static_cast(std::floor(std::log10(m_maxValue)) + 1); + + char out_number[maxDigits + 1]; + Gui::requestKeyboardInput("Input value", "Enter a number for this value to be set to.", std::to_string(m_currValue).c_str(), SwkbdType_NumPad, out_number, maxDigits); + + if (isNumber(std::string(out_number))) + Widget::setIntegerValue( + Widget::m_interpreter->evaluateEquation(m_writeEquation, + Widget::m_interpreter->evaluateEquation(m_readEquation, + std::min(std::max(static_cast(atoi(out_number)), + m_minValue), m_maxValue)))); + + m_currValue = Widget::m_interpreter->evaluateEquation(m_readEquation, Widget::getIntegerValue()); +}